home *** CD-ROM | disk | FTP | other *** search
/ InterCD 2000 September / september_2000.iso / intercd / root / ^Linux / WindowMaker / src / window.c < prev    next >
Encoding:
C/C++ Source or Header  |  2000-03-27  |  82.0 KB  |  3,033 lines

  1. /* window.c - client window managing stuffs
  2.  * 
  3.  *  Window Maker window manager
  4.  * 
  5.  *  Copyright (c) 1997, 1998 Alfredo K. Kojima
  6.  * 
  7.  *  This program is free software; you can redistribute it and/or modify
  8.  *  it under the terms of the GNU General Public License as published by
  9.  *  the Free Software Foundation; either version 2 of the License, or
  10.  *  (at your option) any later version.
  11.  *
  12.  *  This program is distributed in the hope that it will be useful,
  13.  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
  14.  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  15.  *  GNU General Public License for more details.
  16.  *
  17.  *  You should have received a copy of the GNU General Public License
  18.  *  along with this program; if not, write to the Free Software
  19.  *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, 
  20.  *  USA.
  21.  */
  22.  
  23. #include "wconfig.h"
  24.  
  25. #include <X11/Xlib.h>
  26. #include <X11/Xutil.h>
  27. #ifdef SHAPE
  28. #include <X11/extensions/shape.h>
  29. #endif
  30. #ifdef KEEP_XKB_LOCK_STATUS     
  31. #include <X11/XKBlib.h>         
  32. #endif /* KEEP_XKB_LOCK_STATUS */
  33. #include <stdlib.h>
  34. #include <stdio.h>
  35. #include <string.h>
  36.  
  37.  
  38. #include "WindowMaker.h"
  39. #include "GNUstep.h"
  40. #include "wcore.h"
  41. #include "framewin.h"
  42. #include "texture.h"
  43. #include "window.h"
  44. #include "winspector.h"
  45. #include "icon.h"
  46. #include "properties.h"
  47. #include "actions.h"
  48. #include "client.h"
  49. #include "funcs.h"
  50. #include "keybind.h"
  51. #include "stacking.h"
  52. #include "defaults.h"
  53. #include "workspace.h"
  54.  
  55.  
  56. #ifdef MWM_HINTS
  57. # include "motif.h"
  58. #endif
  59. #ifdef KWM_HINTS
  60. # include "kwm.h"
  61. #endif
  62. #ifdef GNOME_STUFF
  63. # include "gnome.h"
  64. #endif
  65. #ifdef OLWM_HINTS
  66. # include "openlook.h"
  67. #endif
  68.  
  69. /****** Global Variables ******/
  70.  
  71. extern WShortKey wKeyBindings[WKBD_LAST];
  72.  
  73. #ifdef SHAPE
  74. extern Bool wShapeSupported;
  75. #endif
  76.  
  77. /* contexts */
  78. extern XContext wWinContext;
  79.  
  80. /* cursors */
  81. extern Cursor wCursor[WCUR_LAST];
  82.  
  83. /* protocol atoms */
  84. extern Atom _XA_WM_DELETE_WINDOW;
  85. extern Atom _XA_GNUSTEP_WM_MINIATURIZE_WINDOW;
  86.  
  87. extern Atom _XA_WINDOWMAKER_STATE;
  88.  
  89. extern WPreferences wPreferences;
  90.  
  91. #define MOD_MASK wPreferences.modifier_mask
  92.  
  93. extern Time LastTimestamp;
  94.  
  95. /* superfluous... */
  96. extern void DoWindowBirth(WWindow*);
  97.  
  98.  
  99. /***** Local Stuff *****/
  100.  
  101.  
  102. static WWindowState *windowState=NULL;
  103.  
  104.  
  105.  
  106. /* local functions */
  107. static FocusMode getFocusMode(WWindow *wwin);
  108.  
  109. static int getSavedState(Window window, WSavedState **state);
  110.  
  111. static void setupGNUstepHints(WWindow *wwin, GNUstepWMAttributes *gs_hints);
  112.  
  113. /* event handlers */
  114.  
  115.  
  116. /* frame window (during window grabs) */
  117. static void frameMouseDown(WObjDescriptor *desc, XEvent *event);
  118.  
  119. /* close button */
  120. static void windowCloseClick(WCoreWindow *sender, void *data, XEvent *event);
  121. static void windowCloseDblClick(WCoreWindow *sender, void *data, XEvent *event);
  122.  
  123. /* iconify button */
  124. static void windowIconifyClick(WCoreWindow *sender, void *data, XEvent *event);
  125.  
  126. #ifdef XKB_BUTTON_HINT
  127. static void windowLanguageClick(WCoreWindow *sender, void *data, XEvent *event);
  128. #endif
  129.  
  130. static void titlebarMouseDown(WCoreWindow *sender, void *data, XEvent *event);
  131. static void titlebarDblClick(WCoreWindow *sender, void *data, XEvent *event);
  132.  
  133. static void resizebarMouseDown(WCoreWindow *sender, void *data, XEvent *event);
  134.  
  135.  
  136. /****** Notification Observers ******/
  137.  
  138. static void
  139. appearanceObserver(void *self, WMNotification *notif)
  140. {
  141.     WWindow *wwin = (WWindow*)self;
  142.     int flags = (int)WMGetNotificationClientData(notif);
  143.  
  144.     if (!wwin->frame || (!wwin->frame->titlebar && !wwin->frame->resizebar))
  145.     return;
  146.  
  147.     if (flags & WFontSettings) {
  148.         wWindowConfigureBorders(wwin);
  149.         if(wwin->flags.shaded) {
  150.             wFrameWindowResize(wwin->frame, wwin->frame->core->width,
  151.                     wwin->frame->top_width - 1);
  152.  
  153.             wwin->client.y = wwin->frame_y - wwin->client.height 
  154.                 + wwin->frame->top_width;
  155.             wWindowSynthConfigureNotify(wwin);
  156.         }
  157.     }
  158.     if (flags & WTextureSettings) {
  159.     wwin->frame->flags.need_texture_remake = 1;
  160.     }
  161.     if (flags & (WTextureSettings | WColorSettings)) {
  162.     if (wwin->frame->titlebar)
  163.         XClearWindow(dpy, wwin->frame->titlebar->window);
  164.  
  165.     wFrameWindowPaint(wwin->frame);
  166.     }
  167. }
  168.  
  169. /************************************/
  170.  
  171. WWindow*
  172. wWindowFor(Window window)
  173. {
  174.     WObjDescriptor *desc;
  175.  
  176.     if (window==None)
  177.       return NULL;
  178.  
  179.     if (XFindContext(dpy, window, wWinContext, (XPointer*)&desc)==XCNOENT)
  180.       return NULL;
  181.  
  182.     if (desc->parent_type==WCLASS_WINDOW)
  183.       return desc->parent;
  184.     else if (desc->parent_type==WCLASS_FRAME) {
  185.     WFrameWindow *frame = (WFrameWindow*)desc->parent;
  186.     if (frame->flags.is_client_window_frame)
  187.         return frame->child;
  188.     }
  189.  
  190.     return NULL;
  191. }
  192.  
  193.  
  194. WWindow*
  195. wWindowCreate()
  196. {
  197.     WWindow *wwin;
  198.     
  199.     wwin = wmalloc(sizeof(WWindow));
  200.     wretain(wwin);
  201.  
  202.     memset(wwin, 0, sizeof(WWindow));
  203.  
  204.     wwin->client_descriptor.handle_mousedown = frameMouseDown;
  205.     wwin->client_descriptor.parent = wwin;
  206.     wwin->client_descriptor.self = wwin;
  207.     wwin->client_descriptor.parent_type = WCLASS_WINDOW;
  208.  
  209.     return wwin;
  210. }
  211.  
  212.  
  213. void
  214. wWindowDestroy(WWindow *wwin)
  215. {
  216.     int i;
  217.  
  218.     if (wwin->screen_ptr->cmap_window == wwin) {
  219.     wwin->screen_ptr->cmap_window = NULL;
  220.     }
  221.     
  222.     WMRemoveNotificationObserver(wwin);
  223.     
  224.     wwin->flags.destroyed = 1;
  225.  
  226.     for (i = 0; i < MAX_WINDOW_SHORTCUTS; i++) {
  227.     if (!wwin->screen_ptr->shortcutWindows[i])
  228.         continue;
  229.  
  230.     WMRemoveFromBag(wwin->screen_ptr->shortcutWindows[i], wwin);
  231.  
  232.     if (!WMGetBagItemCount(wwin->screen_ptr->shortcutWindows[i])) {
  233.         WMFreeBag(wwin->screen_ptr->shortcutWindows[i]);
  234.         wwin->screen_ptr->shortcutWindows[i] = NULL;
  235.     }
  236.     }
  237.  
  238.     if (wwin->normal_hints)
  239.       XFree(wwin->normal_hints);
  240.     
  241.     if (wwin->wm_hints)
  242.       XFree(wwin->wm_hints);
  243.     
  244.     if (wwin->wm_instance)
  245.       XFree(wwin->wm_instance);
  246.  
  247.     if (wwin->wm_class)
  248.       XFree(wwin->wm_class);
  249.  
  250.     if (wwin->wm_gnustep_attr)
  251.       free(wwin->wm_gnustep_attr);
  252.  
  253.     if (wwin->cmap_windows)
  254.       XFree(wwin->cmap_windows);
  255.  
  256.     XDeleteContext(dpy, wwin->client_win, wWinContext);
  257.  
  258.     if (wwin->frame)
  259.     wFrameWindowDestroy(wwin->frame);
  260.  
  261.     if (wwin->icon) {
  262.     RemoveFromStackList(wwin->icon->core);
  263.         wIconDestroy(wwin->icon);
  264.         if (wPreferences.auto_arrange_icons)
  265.             wArrangeIcons(wwin->screen_ptr, True);
  266.     }
  267.     wrelease(wwin);
  268. }
  269.  
  270.  
  271.  
  272.  
  273. static void
  274. setupGNUstepHints(WWindow *wwin, GNUstepWMAttributes *gs_hints)
  275. {
  276.     if (gs_hints->flags & GSWindowStyleAttr) {
  277.     if (gs_hints->window_style == WMBorderlessWindowMask) {
  278.         wwin->client_flags.no_border = 1;
  279.         wwin->client_flags.no_titlebar = 1;
  280.         wwin->client_flags.no_closable = 1;
  281.         wwin->client_flags.no_miniaturizable = 1;
  282.         wwin->client_flags.no_resizable = 1;
  283.         wwin->client_flags.no_close_button = 1;
  284.         wwin->client_flags.no_miniaturize_button = 1;
  285.         wwin->client_flags.no_resizebar = 1;
  286.     } else {
  287.         wwin->client_flags.no_close_button =
  288.         ((gs_hints->window_style & WMClosableWindowMask)?0:1);
  289.  
  290.         wwin->client_flags.no_closable =
  291.         ((gs_hints->window_style & WMClosableWindowMask)?0:1);
  292.  
  293.         wwin->client_flags.no_miniaturize_button =
  294.         ((gs_hints->window_style & WMMiniaturizableWindowMask)?0:1);
  295.  
  296.         wwin->client_flags.no_miniaturizable = 
  297.         wwin->client_flags.no_miniaturize_button;
  298.  
  299.         wwin->client_flags.no_resizebar =
  300.         ((gs_hints->window_style & WMResizableWindowMask)?0:1);
  301.  
  302.         wwin->client_flags.no_resizable = wwin->client_flags.no_resizebar;
  303.  
  304.         /* these attributes supposedly imply in the existence
  305.          * of a titlebar */
  306.         if (gs_hints->window_style & (WMResizableWindowMask|
  307.                       WMClosableWindowMask|
  308.                       WMMiniaturizableWindowMask)) {
  309.         wwin->client_flags.no_titlebar = 0;
  310.         } else {
  311.         wwin->client_flags.no_titlebar = 
  312.             ((gs_hints->window_style & WMTitledWindowMask)?0:1);
  313.         }
  314.  
  315.     }
  316.     } else {
  317.     /* setup the defaults */
  318.     wwin->client_flags.no_border = 0;
  319.     wwin->client_flags.no_titlebar = 0;
  320.     wwin->client_flags.no_closable = 0;
  321.     wwin->client_flags.no_miniaturizable = 0;
  322.     wwin->client_flags.no_resizable = 0;
  323.     wwin->client_flags.no_close_button = 0;
  324.     wwin->client_flags.no_miniaturize_button = 0;
  325.     wwin->client_flags.no_resizebar = 0;
  326.     }
  327.     if (gs_hints->extra_flags & GSNoApplicationIconFlag) {
  328.     wwin->client_flags.no_appicon = 1;
  329.     }
  330. }
  331.  
  332.  
  333. void
  334. wWindowCheckAttributeSanity(WWindow *wwin, WWindowAttributes *wflags,
  335.                 WWindowAttributes *mask)
  336. {
  337.     if (wflags->no_appicon && mask->no_appicon)
  338.     wflags->emulate_appicon = 0;
  339.  
  340.     if (wwin->main_window!=None) {
  341.     WApplication *wapp = wApplicationOf(wwin->main_window);
  342.     if (wapp && !wapp->flags.emulated)
  343.         wflags->emulate_appicon = 0;
  344.     }
  345.     
  346.     if (wwin->transient_for!=None 
  347.     && wwin->transient_for!=wwin->screen_ptr->root_win)
  348.     wflags->emulate_appicon = 0;
  349.     
  350.     if (wflags->sunken && mask->sunken && wflags->floating && mask->floating)
  351.     wflags->sunken = 0;
  352. }
  353.  
  354.  
  355.  
  356. void
  357. wWindowSetupInitialAttributes(WWindow *wwin, int *level, int *workspace)
  358. {
  359.     WScreen *scr = wwin->screen_ptr;
  360.  
  361.     /* sets global default stuff */
  362.     wDefaultFillAttributes(scr, wwin->wm_instance, wwin->wm_class,
  363.                &wwin->client_flags, NULL, True);
  364.     /*
  365.      * Decoration setting is done in this precedence (lower to higher)
  366.      * - use global default in the resource database
  367.      * - guess some settings
  368.      * - use GNUstep/external window attributes
  369.      * - set hints specified for the app in the resource DB
  370.      * 
  371.      */
  372.     WSETUFLAG(wwin, broken_close, 0);
  373.  
  374.     if (wwin->protocols.DELETE_WINDOW)
  375.     WSETUFLAG(wwin, kill_close, 0);
  376.     else
  377.     WSETUFLAG(wwin, kill_close, 1);
  378.  
  379.     /* transients can't be iconified or maximized */
  380.     if (wwin->transient_for) {
  381.     WSETUFLAG(wwin, no_miniaturizable, 1);
  382.     WSETUFLAG(wwin, no_miniaturize_button, 1);
  383.     }
  384.  
  385.     /* if the window can't be resized, remove the resizebar */
  386.     if (wwin->normal_hints->flags & (PMinSize|PMaxSize)
  387.     && (wwin->normal_hints->min_width==wwin->normal_hints->max_width)
  388.     && (wwin->normal_hints->min_height==wwin->normal_hints->max_height)) {
  389.     WSETUFLAG(wwin, no_resizable, 1);
  390.     WSETUFLAG(wwin, no_resizebar, 1);
  391.     }
  392.     
  393.     /* set GNUstep window attributes */
  394.     if (wwin->wm_gnustep_attr) {
  395.     setupGNUstepHints(wwin, wwin->wm_gnustep_attr);
  396.  
  397.     if (wwin->wm_gnustep_attr->flags & GSWindowLevelAttr) {
  398.  
  399.         switch (wwin->wm_gnustep_attr->window_level) {
  400.          case WMNormalWindowLevel:
  401.         *level = WMNormalLevel;
  402.         break;
  403.          case WMFloatingWindowLevel:
  404.         *level = WMFloatingLevel;
  405.         break;
  406.          case WMDockWindowLevel:
  407.         *level = WMDockLevel;
  408.         break;
  409.          case WMSubmenuWindowLevel:
  410.         *level = WMSubmenuLevel;
  411.         break;
  412.          case WMMainMenuWindowLevel:
  413.         *level = WMMainMenuLevel;
  414.         break;
  415.          default:
  416.         *level = WMNormalLevel;
  417.         break;
  418.         }
  419.     } else {
  420.         /* setup defaults */
  421.         *level = WMNormalLevel;
  422.     }
  423.     } else {
  424.     int tmp_workspace = -1;
  425.     int tmp_level = -1;
  426.     
  427. #ifdef MWM_HINTS
  428.     wMWMCheckClientHints(wwin);
  429. #endif /* MWM_HINTS */
  430.  
  431. #ifdef KWM_HINTS
  432.     wKWMCheckClientHints(wwin, &tmp_level, &tmp_workspace);
  433. #endif /* KWM_HINTS */
  434.     
  435. #ifdef GNOME_STUFF
  436.     wGNOMECheckClientHints(wwin, &tmp_level, &tmp_workspace);
  437. #endif /* GNOME_STUFF */
  438.  
  439. #ifdef OLWM_HINTS
  440.     wOLWMCheckClientHints(wwin);
  441. #endif /* OLWM_HINTS */
  442.  
  443.     if (tmp_level < 0) {
  444.         if (WFLAGP(wwin, floating))
  445.         *level = WMFloatingLevel;
  446.         else if (WFLAGP(wwin, sunken))
  447.         *level = WMSunkenLevel;
  448.         else
  449.         *level = WMNormalLevel;
  450.     } else {
  451.         *level = tmp_level;
  452.     }
  453.  
  454.     if (tmp_workspace >= 0) {
  455.         *workspace = tmp_workspace % scr->workspace_count;
  456.     }
  457.     }
  458.  
  459.     /*
  460.      * Set attributes specified only for that window/class.
  461.      * This might do duplicate work with the 1st wDefaultFillAttributes().
  462.      */
  463.     wDefaultFillAttributes(scr, wwin->wm_instance, wwin->wm_class, 
  464.                &wwin->user_flags, &wwin->defined_user_flags,
  465.                False);
  466.     /*
  467.      * Sanity checks for attributes that depend on other attributes
  468.      */
  469.     if (wwin->user_flags.no_appicon && wwin->defined_user_flags.no_appicon)
  470.     wwin->user_flags.emulate_appicon = 0;
  471.  
  472.     if (wwin->main_window!=None) {
  473.     WApplication *wapp = wApplicationOf(wwin->main_window);
  474.     if (wapp && !wapp->flags.emulated)
  475.         wwin->user_flags.emulate_appicon = 0;
  476.     }
  477.     
  478.     if (wwin->transient_for!=None 
  479.     && wwin->transient_for!=wwin->screen_ptr->root_win)
  480.     wwin->user_flags.emulate_appicon = 0;
  481.     
  482.     if (wwin->user_flags.sunken && wwin->defined_user_flags.sunken 
  483.     && wwin->user_flags.floating && wwin->defined_user_flags.floating)
  484.     wwin->user_flags.sunken = 0;
  485.  
  486.     WSETUFLAG(wwin, no_shadeable, WFLAGP(wwin, no_titlebar));
  487. }
  488.  
  489.  
  490.  
  491.  
  492. Bool
  493. wWindowCanReceiveFocus(WWindow *wwin)
  494. {
  495.     if (!wwin->flags.mapped && (!wwin->flags.shaded || wwin->flags.hidden))
  496.     return False;
  497.     if (WFLAGP(wwin, no_focusable) || wwin->flags.miniaturized)
  498.     return False;
  499.     if (wwin->frame->workspace != wwin->screen_ptr->current_workspace)
  500.     return False;
  501.  
  502.     return True;
  503. }
  504.  
  505.  
  506. Bool
  507. wWindowObscuresWindow(WWindow *wwin, WWindow *obscured)
  508. {
  509.     int w1, h1, w2, h2;
  510.  
  511.     w1 = wwin->frame->core->width;
  512.     h1 = wwin->frame->core->height;
  513.     w2 = obscured->frame->core->width;
  514.     h2 = obscured->frame->core->height;
  515.  
  516.     if (!IS_OMNIPRESENT(wwin) && !IS_OMNIPRESENT(obscured)
  517.     && wwin->frame->workspace != obscured->frame->workspace)
  518.     return False;
  519.  
  520.     if (wwin->frame_x + w1 < obscured->frame_x
  521.     || wwin->frame_y + h1 < obscured->frame_y
  522.     || wwin->frame_x > obscured->frame_x + w2
  523.     || wwin->frame_y > obscured->frame_y + h2) {
  524.     return False;
  525.     }
  526.  
  527.     return True;
  528. }
  529.  
  530.  
  531. /*
  532.  *----------------------------------------------------------------
  533.  * wManageWindow--
  534.  *     reparents the window and allocates a descriptor for it.
  535.  * Window manager hints and other hints are fetched to configure
  536.  * the window decoration attributes and others. User preferences
  537.  * for the window are used if available, to configure window 
  538.  * decorations and some behaviour.
  539.  *     If in startup, windows that are override redirect,
  540.  * unmapped and never were managed and are Withdrawn are not
  541.  * managed.
  542.  * 
  543.  * Returns:
  544.  *     the new window descriptor
  545.  * 
  546.  * Side effects:
  547.  *     The window is reparented and appropriate notification
  548.  * is done to the client. Input mask for the window is setup.
  549.  *     The window descriptor is also associated with various window 
  550.  * contexts and inserted in the head of the window list.
  551.  * Event handler contexts are associated for some objects 
  552.  * (buttons, titlebar and resizebar)
  553.  * 
  554.  *---------------------------------------------------------------- 
  555.  */
  556. WWindow*
  557. wManageWindow(WScreen *scr, Window window)
  558. {
  559.     WWindow *wwin;
  560.     int x, y;
  561.     unsigned width, height;
  562.     XWindowAttributes wattribs;    
  563.     XSetWindowAttributes attribs;
  564.     WWindowState *win_state;
  565.     WWindow *transientOwner = NULL;
  566.     int window_level;
  567.     int wm_state;
  568.     int foo;
  569.     int workspace = -1;
  570.     char *title;
  571.     Bool withdraw = False;
  572.  
  573.     /* mutex. */
  574.     /* XGrabServer(dpy); */
  575.     XSync(dpy, False);
  576.     /* make sure the window is still there */
  577.     if (!XGetWindowAttributes(dpy, window, &wattribs)) {
  578.     XUngrabServer(dpy);
  579.     return NULL;
  580.     }
  581.  
  582.     /* if it's an override-redirect, ignore it */
  583.     if (wattribs.override_redirect) {
  584.     XUngrabServer(dpy);
  585.     return NULL;
  586.     }
  587.  
  588.     wm_state = PropGetWindowState(window);
  589.  
  590.     /* if it's startup and the window is unmapped, don't manage it */
  591.     if (scr->flags.startup && wm_state < 0 && wattribs.map_state==IsUnmapped) {
  592.     XUngrabServer(dpy);
  593.     return NULL;
  594.     }
  595.  
  596.     if (!wFetchName(dpy, window, &title)) {
  597.     title = NULL;
  598.     }
  599.  
  600. #ifdef KWM_HINTS
  601.     if (title && !wKWMManageableClient(scr, window, title)) {
  602.     XFree(title);
  603.     XUngrabServer(dpy);
  604.     return NULL;
  605.     }
  606. #endif /* KWM_HINTS */
  607.  
  608.  
  609.     wwin = wWindowCreate();
  610.  
  611.     XSaveContext(dpy, window, wWinContext, (XPointer)&wwin->client_descriptor);
  612.  
  613. #ifdef DEBUG
  614.     printf("managing window %x\n", (unsigned)window);
  615. #endif
  616.  
  617. #ifdef SHAPE
  618.     if (wShapeSupported) {
  619.     int junk;
  620.     unsigned int ujunk;
  621.     int b_shaped;
  622.     
  623.     XShapeSelectInput(dpy, window, ShapeNotifyMask);
  624.     XShapeQueryExtents(dpy, window, &b_shaped, &junk, &junk, &ujunk, 
  625.                &ujunk, &junk, &junk, &junk, &ujunk, &ujunk);
  626.     wwin->flags.shaped = b_shaped;
  627.     }
  628. #endif
  629.     
  630.     /*
  631.      *--------------------------------------------------
  632.      * 
  633.      * Get hints and other information in properties
  634.      *
  635.      *-------------------------------------------------- 
  636.      */
  637.     PropGetWMClass(window, &wwin->wm_class, &wwin->wm_instance);
  638.  
  639.     /* setup descriptor */
  640.     wwin->client_win = window;
  641.     wwin->screen_ptr = scr;
  642.  
  643.     wwin->old_border_width = wattribs.border_width;
  644.  
  645.     wwin->event_mask = CLIENT_EVENTS;
  646.     attribs.event_mask = CLIENT_EVENTS;
  647.     attribs.do_not_propagate_mask = ButtonPressMask | ButtonReleaseMask;
  648.     attribs.save_under = False;
  649.     XChangeWindowAttributes(dpy, window, CWEventMask|CWDontPropagate
  650.                 |CWSaveUnder, &attribs);    
  651.     XSetWindowBorderWidth(dpy, window, 0);
  652.  
  653.     /* get hints from GNUstep app */
  654.     if (wwin->wm_class != 0 && strcmp(wwin->wm_class, "GNUstep") == 0) {
  655.     wwin->flags.is_gnustep = 1;
  656.     }
  657.     if (!PropGetGNUstepWMAttr(window, &wwin->wm_gnustep_attr)) {
  658.     wwin->wm_gnustep_attr = NULL;
  659.     }
  660.  
  661.     wwin->client_leader = PropGetClientLeader(window);
  662.     if (wwin->client_leader!=None)
  663.     wwin->main_window = wwin->client_leader;
  664.  
  665.     wwin->wm_hints = XGetWMHints(dpy, window);
  666.  
  667.     if (wwin->wm_hints)  {
  668.     if (wwin->wm_hints->flags & StateHint) {
  669.  
  670.         if (wwin->wm_hints->initial_state == IconicState) {
  671.  
  672.         wwin->flags.miniaturized = 1;
  673.  
  674.         } else if (wwin->wm_hints->initial_state == WithdrawnState) {
  675.  
  676.         withdraw = True;
  677.         }
  678.     }
  679.  
  680.     if (wwin->wm_hints->flags & WindowGroupHint) {
  681.         wwin->group_id = wwin->wm_hints->window_group;
  682.         /* window_group has priority over CLIENT_LEADER */
  683.         wwin->main_window = wwin->group_id;
  684.     } else {
  685.         wwin->group_id = None;
  686.     }
  687.  
  688.     if (wwin->wm_hints->flags & UrgencyHint)
  689.       wwin->flags.urgent = 1;
  690.     } else {
  691.     wwin->group_id = None;
  692.     }
  693.  
  694.     PropGetProtocols(window, &wwin->protocols);
  695.     
  696.     if (!XGetTransientForHint(dpy, window, &wwin->transient_for)) {
  697.     wwin->transient_for = None;
  698.     } else {
  699.     if (wwin->transient_for==None || wwin->transient_for==window) {
  700.         wwin->transient_for = scr->root_win;
  701.     } else {
  702.         transientOwner = wWindowFor(wwin->transient_for);
  703.         if (transientOwner && transientOwner->main_window!=None) {
  704.         wwin->main_window = transientOwner->main_window;
  705.             } /*else {
  706.         wwin->main_window = None;
  707.             }*/
  708.     }
  709.     }
  710.  
  711.     /* guess the focus mode */
  712.     wwin->focus_mode = getFocusMode(wwin);
  713.  
  714.     /* get geometry stuff */
  715.     wClientGetNormalHints(wwin, &wattribs, True, &x, &y, &width, &height);
  716.  
  717.     /* get colormap windows */
  718.     GetColormapWindows(wwin);
  719.  
  720.     /*
  721.      *--------------------------------------------------
  722.      * 
  723.      * Setup the decoration/window attributes and
  724.      * geometry
  725.      * 
  726.      *--------------------------------------------------
  727.      */
  728.  
  729.     wWindowSetupInitialAttributes(wwin, &window_level, &workspace);
  730.  
  731. #ifdef OLWM_HINTS
  732.     if (wwin->client_flags.olwm_transient && wwin->transient_for==None
  733.     && wwin->group_id != None && wwin->group_id != window) {
  734.  
  735.     transientOwner = wWindowFor(wwin->group_id);
  736.  
  737.     if (transientOwner) {
  738.         wwin->transient_for = wwin->group_id;
  739.  
  740.         /* transients can't be iconified or maximized */
  741.         if (wwin->transient_for) {
  742.         WSETUFLAG(wwin, no_miniaturizable, 1);
  743.         WSETUFLAG(wwin, no_miniaturize_button, 1);
  744.         }
  745.     }
  746.     }
  747. #endif /* OLWM_HINTS */
  748.  
  749.     /*
  750.      * Make broken apps behave as a nice app.
  751.      */
  752.     if (WFLAGP(wwin, emulate_appicon)) {
  753.     wwin->main_window = wwin->client_win;
  754.     }
  755.  
  756.     /*
  757.      *------------------------------------------------------------
  758.      *
  759.      * Setup the initial state of the window
  760.      *
  761.      *------------------------------------------------------------
  762.      */
  763.  
  764.     if (WFLAGP(wwin, start_miniaturized) && !WFLAGP(wwin, no_miniaturizable)) {
  765.     wwin->flags.miniaturized = 1;
  766.     }
  767.  
  768.     if (WFLAGP(wwin, start_maximized) && !WFLAGP(wwin, no_resizable)) {
  769.     wwin->flags.maximized = MAX_VERTICAL|MAX_HORIZONTAL;
  770.     }
  771.  
  772. #ifdef GNOME_STUFF
  773.     wGNOMECheckInitialClientState(wwin);
  774. #endif
  775. #ifdef KWM_HINTS
  776.     wKWMCheckClientInitialState(wwin);
  777. #endif
  778.  
  779.     /* apply previous state if it exists and we're in startup */
  780.     if (scr->flags.startup && wm_state >= 0) {
  781.  
  782.     if (wm_state == IconicState) {
  783.  
  784.         wwin->flags.miniaturized = 1;
  785.  
  786.     } else if (wm_state == WithdrawnState) {
  787.  
  788.         withdraw = True;
  789.     }
  790.     }
  791.  
  792.     /* if there is a saved state (from file), restore it */
  793.     win_state = NULL;
  794.     if (wwin->main_window!=None/* && wwin->main_window!=window*/) {
  795.         win_state = (WWindowState*)wWindowGetSavedState(wwin->main_window);
  796.     } else {
  797.         win_state = (WWindowState*)wWindowGetSavedState(window);
  798.     }
  799.     if (win_state && !withdraw) {
  800.  
  801.         if (win_state->state->hidden>0)
  802.             wwin->flags.hidden = win_state->state->hidden;
  803.  
  804.         if (win_state->state->shaded>0 && !WFLAGP(wwin, no_shadeable))
  805.             wwin->flags.shaded = win_state->state->shaded;
  806.  
  807.         if (win_state->state->miniaturized>0 &&
  808.         !WFLAGP(wwin, no_miniaturizable)) {
  809.             wwin->flags.miniaturized = win_state->state->miniaturized;
  810.         }
  811.         if (!IS_OMNIPRESENT(wwin)) {
  812.             int w = wDefaultGetStartWorkspace(scr, wwin->wm_instance,
  813.                                               wwin->wm_class);
  814.             if (w < 0 || w >= scr->workspace_count) {
  815.                 workspace = win_state->state->workspace;
  816.                 if (workspace >= scr->workspace_count)
  817.                     workspace = scr->current_workspace;
  818.             } else {
  819.                 workspace = w;
  820.             }
  821.         } else {
  822.             workspace = scr->current_workspace;
  823.         }
  824.     }
  825.  
  826.     /* if we're restarting, restore saved state (from hints). 
  827.      * This will overwrite previous */
  828.     {
  829.     WSavedState *wstate;
  830.  
  831.     if (getSavedState(window, &wstate)) {
  832.         wwin->flags.shaded = wstate->shaded;
  833.         wwin->flags.hidden = wstate->hidden;
  834.         wwin->flags.miniaturized = wstate->miniaturized;
  835.         workspace = wstate->workspace;
  836.  
  837.         if (scr->flags.startup && wstate->window_shortcuts > 0) {
  838.         int i;
  839.  
  840.         for (i = 0; i < MAX_WINDOW_SHORTCUTS; i++) {
  841.             if (wstate->window_shortcuts & (1<<i)) {
  842.             if (!scr->shortcutWindows[i])
  843.                 scr->shortcutWindows[i] = WMCreateBag(4);
  844.  
  845.             WMPutInBag(scr->shortcutWindows[i], wwin);
  846.             }
  847.         }
  848.         }
  849.         free(wstate);
  850.     }
  851.     }
  852.  
  853.     /* don't let transients start miniaturized if their owners are not */
  854.     if (transientOwner && !transientOwner->flags.miniaturized
  855.     && wwin->flags.miniaturized && !withdraw) {
  856.     wwin->flags.miniaturized = 0;
  857.     if (wwin->wm_hints)
  858.         wwin->wm_hints->initial_state = NormalState;
  859.     }
  860.  
  861.     /* set workspace on which the window starts */    
  862.     if (workspace >= 0) {
  863.     if (workspace > scr->workspace_count-1) {
  864.         workspace = workspace % scr->workspace_count;
  865.     }
  866.     } else {
  867.     int w;
  868.  
  869.     w = wDefaultGetStartWorkspace(scr, wwin->wm_instance, wwin->wm_class);
  870.  
  871.         if (w >= 0 && w < scr->workspace_count && !(IS_OMNIPRESENT(wwin))) {
  872.  
  873.             workspace = w;
  874.  
  875.         } else {
  876.         if (wPreferences.open_transients_with_parent && transientOwner) {
  877.  
  878.         workspace = transientOwner->frame->workspace;
  879.  
  880.         } else {
  881.  
  882.         workspace = scr->current_workspace;
  883.         }
  884.         }
  885.     }
  886.  
  887.     /* setup window geometry */
  888.     if (win_state && win_state->state->use_geometry) {
  889.         width = win_state->state->w;
  890.         height = win_state->state->h;
  891.     }
  892.     wWindowConstrainSize(wwin, &width, &height);
  893.  
  894.     /* do not ask for window placement if the window is
  895.      * transient, during startup, if the initial workspace is another one
  896.      * or if the window wants to start iconic.
  897.      * If geometry was saved, restore it. */
  898.     {
  899.     Bool dontBring = False;
  900.  
  901.     if (win_state && win_state->state->use_geometry) {
  902.         x = win_state->state->x;
  903.         y = win_state->state->y;
  904.     } else if ((wwin->transient_for==None
  905.             || wPreferences.window_placement!=WPM_MANUAL)
  906.            && !scr->flags.startup 
  907.            && workspace == scr->current_workspace
  908.            && !wwin->flags.miniaturized
  909.            && !wwin->flags.maximized
  910.            && !(wwin->normal_hints->flags & (USPosition|PPosition))) {
  911.         
  912.         if (transientOwner && transientOwner->flags.mapped) {
  913.         int offs = WMAX(20, 2*transientOwner->frame->top_width);
  914.         
  915.         x = transientOwner->frame_x + 
  916.             abs((transientOwner->frame->core->width - width)/2) + offs;
  917.         y = transientOwner->frame_y +
  918.             abs((transientOwner->frame->core->height - height)/3) + offs;
  919.  
  920.         if (x < 0)
  921.             x = 0;
  922.         else if (x + width > scr->scr_width)
  923.             x = scr->scr_width - width;
  924.  
  925.         if (y < 0)
  926.             y = 0;
  927.         else if (y + height > scr->scr_height)
  928.             y = scr->scr_height - height;
  929.         } else {
  930.         PlaceWindow(wwin, &x, &y, width, height);
  931.         }
  932.         if (wPreferences.window_placement == WPM_MANUAL)
  933.         dontBring = True;
  934.     } 
  935.  
  936.     if (WFLAGP(wwin, dont_move_off) && dontBring)
  937.         wScreenBringInside(scr, &x, &y, width, height);
  938.     }
  939.  
  940.     if (wwin->flags.urgent) {
  941.     if (!IS_OMNIPRESENT(wwin))
  942.         wwin->flags.omnipresent ^= 1;
  943.     }
  944.  
  945.     /*
  946.      *--------------------------------------------------
  947.      * 
  948.      * Create frame, borders and do reparenting
  949.      *
  950.      *--------------------------------------------------
  951.      */
  952.     foo = WFF_LEFT_BUTTON | WFF_RIGHT_BUTTON;
  953. #ifdef XKB_BUTTON_HINT
  954.     if (wPreferences.modelock)
  955.         foo |= WFF_LANGUAGE_BUTTON;
  956. #endif
  957.     if (!WFLAGP(wwin, no_titlebar))
  958.     foo |= WFF_TITLEBAR;
  959.     if (!WFLAGP(wwin, no_resizebar))
  960.     foo |= WFF_RESIZEBAR;
  961.     if (!WFLAGP(wwin, no_border))
  962.     foo |= WFF_BORDER;
  963.  
  964.     wwin->frame = wFrameWindowCreate(scr, window_level, 
  965.                      x, y, width, height,
  966.                      &wPreferences.window_title_clearance, foo,
  967.                      scr->window_title_texture,
  968.                      scr->resizebar_texture,
  969.                      scr->window_title_pixel, 
  970. #ifdef DRAWSTRING_PLUGIN
  971.                      W_STRING_FTITLE,
  972. #endif
  973.                      &scr->window_title_gc, 
  974.                      &scr->title_font);
  975.  
  976.     wwin->frame->flags.is_client_window_frame = 1;
  977.     wwin->frame->flags.justification = wPreferences.title_justification;
  978.  
  979.     /* setup button images */
  980.     wWindowUpdateButtonImages(wwin);
  981.  
  982.     /* hide unused buttons */
  983.     foo = 0;
  984.     if (WFLAGP(wwin, no_close_button))
  985.     foo |= WFF_RIGHT_BUTTON;
  986.     if (WFLAGP(wwin, no_miniaturize_button))
  987.     foo |= WFF_LEFT_BUTTON;
  988. #ifdef XKB_BUTTON_HINT
  989.     if (WFLAGP(wwin, no_language_button) || WFLAGP(wwin, no_focusable))
  990.     foo |= WFF_LANGUAGE_BUTTON;
  991. #endif
  992.     if (foo!=0)
  993.     wFrameWindowHideButton(wwin->frame, foo);
  994.  
  995.     wwin->frame->child = wwin;
  996.  
  997. #ifdef OLWM_HINTS
  998.     /* emulate olwm push pin. Make the button look as pushed-in for
  999.      * the pinned-out state. When the button is clicked, it will
  1000.      * revert to the normal position, which means the pin is pinned-in.
  1001.      */
  1002.     if (wwin->flags.olwm_push_pin_out)
  1003.     wFrameWindowUpdatePushButton(wwin->frame, True);
  1004. #endif /* OLWM_HINTS */
  1005.  
  1006.     wFrameWindowChangeTitle(wwin->frame, title ? title : DEF_WINDOW_TITLE);
  1007.     if (title)
  1008.     XFree(title);
  1009.  
  1010.     wwin->frame->workspace = workspace;
  1011.  
  1012.     wwin->frame->on_click_left = windowIconifyClick;
  1013. #ifdef XKB_BUTTON_HINT
  1014.     if (wPreferences.modelock)
  1015.         wwin->frame->on_click_language = windowLanguageClick;
  1016. #endif
  1017.  
  1018.     wwin->frame->on_click_right = windowCloseClick;
  1019.     wwin->frame->on_dblclick_right = windowCloseDblClick;
  1020.  
  1021.     wwin->frame->on_mousedown_titlebar = titlebarMouseDown;
  1022.     wwin->frame->on_dblclick_titlebar = titlebarDblClick;
  1023.  
  1024.     wwin->frame->on_mousedown_resizebar = resizebarMouseDown;
  1025.  
  1026.  
  1027.     XSelectInput(dpy, wwin->client_win,
  1028.          wwin->event_mask & ~StructureNotifyMask);
  1029.  
  1030.     XReparentWindow(dpy, wwin->client_win, wwin->frame->core->window,
  1031.             0, wwin->frame->top_width);
  1032.  
  1033.     XSelectInput(dpy, wwin->client_win, wwin->event_mask);
  1034.  
  1035.  
  1036.     {
  1037.     int gx, gy;
  1038.  
  1039.     wClientGetGravityOffsets(wwin, &gx, &gy);
  1040.  
  1041.     /* if gravity is to the south, account for the border sizes */
  1042.     if (gy > 0)
  1043.         y -= wwin->frame->top_width + wwin->frame->bottom_width;
  1044.     }
  1045.  
  1046.     /* 
  1047.      * wWindowConfigure() will init the client window's size
  1048.      * (wwin->client.{width,height}) and all other geometry
  1049.      * related variables (frame_x,frame_y)
  1050.      */
  1051.     wWindowConfigure(wwin, x, y, width, height);
  1052.  
  1053.     /* to make sure the window receives it's new position after reparenting */
  1054.     wWindowSynthConfigureNotify(wwin);
  1055.  
  1056.     /*
  1057.      *--------------------------------------------------
  1058.      * 
  1059.      * Setup descriptors and save window to internal
  1060.      * lists
  1061.      *
  1062.      *--------------------------------------------------
  1063.      */
  1064.  
  1065.     if (wwin->main_window!=None) {
  1066.     WApplication *app;
  1067.     WWindow *leader;
  1068.  
  1069.     /* Leader windows do not necessary set themselves as leaders.
  1070.      * If this is the case, point the leader of this window to
  1071.      * itself */
  1072.     leader = wWindowFor(wwin->main_window);
  1073.     if (leader && leader->main_window==None) {
  1074.         leader->main_window = leader->client_win;
  1075.     }
  1076.     app = wApplicationCreate(scr, wwin->main_window);
  1077.         if (app) {
  1078.             app->last_workspace = workspace;
  1079.  
  1080.             /*
  1081.              * Do application specific stuff, like setting application
  1082.              * wide attributes.
  1083.              */
  1084.  
  1085.             if (wwin->flags.hidden) {
  1086.                 /* if the window was set to hidden because it was hidden
  1087.                  * in a previous incarnation and that state was restored */
  1088.                 app->flags.hidden = 1;
  1089.             }
  1090.  
  1091.             if (app->flags.hidden) {
  1092.                 wwin->flags.hidden = 1;
  1093.             }
  1094.         }
  1095.     }
  1096.  
  1097.     /* setup the frame descriptor */
  1098.     wwin->frame->core->descriptor.handle_mousedown = frameMouseDown;
  1099.     wwin->frame->core->descriptor.parent = wwin;
  1100.     wwin->frame->core->descriptor.parent_type = WCLASS_WINDOW;
  1101.  
  1102.     /* don't let windows go away if we die */
  1103.     XAddToSaveSet(dpy, window);
  1104.  
  1105.     XLowerWindow(dpy, window);
  1106.  
  1107.     /* if window is in this workspace and should be mapped, then  map it */
  1108.     if (!wwin->flags.miniaturized
  1109.     && (workspace == scr->current_workspace || IS_OMNIPRESENT(wwin))
  1110.         && !wwin->flags.hidden && !withdraw) {
  1111.  
  1112.         /* The following "if" is to avoid crashing of clients that expect
  1113.          * WM_STATE set before they get mapped. Else WM_STATE is set later,
  1114.          * after the return from this function.
  1115.          */
  1116.         if (wwin->wm_hints && (wwin->wm_hints->flags & StateHint)) {
  1117.             wClientSetState(wwin, wwin->wm_hints->initial_state, None);
  1118.         } else {
  1119.             wClientSetState(wwin, NormalState, None);
  1120.         }
  1121.  
  1122. #if 0
  1123.     /* if not auto focus, then map the window under the currently
  1124.      * focused window */
  1125. #define _WIDTH(w) (w)->frame->core->width
  1126. #define _HEIGHT(w) (w)->frame->core->height
  1127.     if (!wPreferences.auto_focus && scr->focused_window
  1128.         && !scr->flags.startup && !transientOwner
  1129.         && ((wWindowObscuresWindow(wwin, scr->focused_window)
  1130.          && (_WIDTH(wwin) > (_WIDTH(scr->focused_window)*5)/3
  1131.              || _HEIGHT(wwin) > (_HEIGHT(scr->focused_window)*5)/3)
  1132.          && WINDOW_LEVEL(scr->focused_window) == WINDOW_LEVEL(wwin))
  1133.         || wwin->flags.maximized)) {
  1134.         MoveInStackListUnder(scr->focused_window->frame->core,
  1135.                  wwin->frame->core);
  1136.     }
  1137. #undef _WIDTH
  1138. #undef _HEIGHT
  1139.  
  1140. #endif
  1141.  
  1142.     if (wPreferences.superfluous && !wPreferences.no_animations
  1143.         && !scr->flags.startup && wwin->transient_for==None
  1144.         /* 
  1145.          * The brain damaged idiotic non-click to focus modes will
  1146.          * have trouble with this because:
  1147.          * 
  1148.          * 1. window is created and mapped by the client
  1149.          * 2. window is mapped by wmaker in small size
  1150.          * 3. window is animated to grow to normal size
  1151.          * 4. this function returns to normal event loop
  1152.          * 5. eventually, the EnterNotify event that would trigger
  1153.          * the window focusing (if the mouse is over that window)
  1154.          * will be processed by wmaker.
  1155.          * But since this event will be rather delayed 
  1156.          * (step 3 has a large delay) the time when the event ocurred
  1157.          * and when it is processed, the client that owns that window
  1158.          * will reject the XSetInputFocus() for it.
  1159.          */
  1160.         && (wPreferences.focus_mode==WKF_CLICK
  1161.         || wPreferences.auto_focus)) {
  1162.         DoWindowBirth(wwin);
  1163.     }
  1164.  
  1165.     wWindowMap(wwin);
  1166.     }
  1167.  
  1168.     /* setup stacking descriptor */
  1169.     if (transientOwner) {
  1170.     /* && wPreferences.on_top_transients */
  1171.     if (transientOwner) {
  1172.         wwin->frame->core->stacking->child_of =
  1173.         transientOwner->frame->core;
  1174.     }
  1175.     } else {
  1176.     wwin->frame->core->stacking->child_of = NULL;
  1177.     }
  1178.  
  1179.  
  1180.     if (!scr->focused_window) {
  1181.     /* first window on the list */
  1182.     wwin->next = NULL;
  1183.     wwin->prev = NULL;
  1184.     scr->focused_window = wwin;
  1185.     } else {
  1186.     WWindow *tmp;
  1187.  
  1188.     /* add window at beginning of focus window list */
  1189.     tmp = scr->focused_window;
  1190.     while (tmp->prev)
  1191.         tmp = tmp->prev;
  1192.     tmp->prev = wwin;
  1193.     wwin->next = tmp;
  1194.     wwin->prev = NULL;
  1195.     }
  1196.  
  1197. #ifdef GNOME_STUFF
  1198.     wGNOMEUpdateClientStateHint(wwin, True);
  1199. #endif
  1200. #ifdef KWM_HINTS
  1201.     wKWMUpdateClientWorkspace(wwin);
  1202.     wKWMUpdateClientStateHint(wwin, KWMAllFlags);
  1203. #endif
  1204.  
  1205.     XUngrabServer(dpy);
  1206.  
  1207.     /*
  1208.      *--------------------------------------------------
  1209.      *
  1210.      * Final preparations before window is ready to go
  1211.      *
  1212.      *--------------------------------------------------
  1213.      */
  1214.  
  1215.     wFrameWindowChangeState(wwin->frame, WS_UNFOCUSED);
  1216.  
  1217.  
  1218.     if (!wwin->flags.miniaturized && workspace == scr->current_workspace
  1219.     && !wwin->flags.hidden) {
  1220.     if (((transientOwner && transientOwner->flags.focused)
  1221.          || wPreferences.auto_focus) && !WFLAGP(wwin, no_focusable))
  1222.         wSetFocusTo(scr, wwin);
  1223.     }
  1224.     wWindowResetMouseGrabs(wwin);
  1225.  
  1226.     if (!WFLAGP(wwin, no_bind_keys)) {
  1227.     wWindowSetKeyGrabs(wwin);
  1228.     }
  1229. #ifdef GNOME_STUFF
  1230.     wGNOMEUpdateClientListHint(scr);
  1231. #endif
  1232. #ifdef KWM_HINTS
  1233.     wwin->flags.kwm_managed = 1;
  1234.  
  1235.     wKWMSendEventMessage(wwin, WKWMAddWindow);
  1236. #endif
  1237.  
  1238.     wColormapInstallForWindow(scr, scr->cmap_window);
  1239.  
  1240.     UpdateSwitchMenu(scr, wwin, ACTION_ADD);
  1241.  
  1242. #ifdef OLWM_HINTS
  1243.     if (wwin->client_flags.olwm_warp_to_pin && wwin->frame->titlebar != NULL
  1244.     && !WFLAGP(wwin, no_close_button) && !withdraw) {
  1245.  
  1246.     XWarpPointer(dpy, None, None, 0, 0, 0, 0,
  1247.              wwin->frame_x + width - wwin->frame->titlebar->height * 2,
  1248.              wwin->frame_y);
  1249.     }
  1250. #endif
  1251.  
  1252.     /*
  1253.      *------------------------------------------------------------
  1254.      * Setup Notification Observers
  1255.      *------------------------------------------------------------
  1256.      */
  1257.     WMAddNotificationObserver(appearanceObserver, wwin,
  1258.                   WNWindowAppearanceSettingsChanged, wwin);
  1259.  
  1260.     
  1261.     /*
  1262.      *--------------------------------------------------
  1263.      * 
  1264.      *  Cleanup temporary stuff
  1265.      *
  1266.      *--------------------------------------------------
  1267.      */
  1268.  
  1269.     if (win_state)
  1270.         wWindowDeleteSavedState(win_state);
  1271.  
  1272.     /* If the window must be withdrawed, then do it now.
  1273.      * Must do some optimization, 'though */
  1274.     if (withdraw) {
  1275.     wwin->flags.mapped = 0;
  1276.     wClientSetState(wwin, WithdrawnState, None);
  1277.     wUnmanageWindow(wwin, True, False);
  1278.     wwin = NULL;
  1279.     }
  1280.  
  1281.     return wwin;
  1282. }
  1283.  
  1284.  
  1285.  
  1286.  
  1287.  
  1288. WWindow*
  1289. wManageInternalWindow(WScreen *scr, Window window, Window owner,
  1290.               char *title, int x, int y, int width, int height)
  1291. {
  1292.     WWindow *wwin;
  1293.     int foo;
  1294.  
  1295.     wwin = wWindowCreate();
  1296.  
  1297.     WMAddNotificationObserver(appearanceObserver, wwin,
  1298.                   WNWindowAppearanceSettingsChanged, wwin);
  1299.  
  1300.     wwin->flags.internal_window = 1;
  1301.  
  1302.     WSETUFLAG(wwin, omnipresent, 1);
  1303.     WSETUFLAG(wwin, no_shadeable, 1);
  1304.     WSETUFLAG(wwin, no_resizable, 1);
  1305.     WSETUFLAG(wwin, no_miniaturizable, 1);
  1306.  
  1307.     wwin->focus_mode = WFM_PASSIVE;
  1308.     
  1309.     wwin->client_win = window;
  1310.     wwin->screen_ptr = scr;
  1311.  
  1312.     wwin->transient_for = owner;
  1313.     
  1314.     wwin->client.x = x;
  1315.     wwin->client.y = y;
  1316.     wwin->client.width = width;
  1317.     wwin->client.height = height;
  1318.    
  1319.     wwin->frame_x = wwin->client.x;
  1320.     wwin->frame_y = wwin->client.y;
  1321.  
  1322.     
  1323.     foo = WFF_RIGHT_BUTTON|WFF_BORDER;
  1324.     foo |= WFF_TITLEBAR;
  1325. #ifdef XKB_BUTTON_HINT
  1326.     foo |= WFF_LANGUAGE_BUTTON;
  1327. #endif
  1328.  
  1329.     wwin->frame = wFrameWindowCreate(scr, WMFloatingLevel,
  1330.                      wwin->frame_x, wwin->frame_y,
  1331.                      width, height,
  1332.                      &wPreferences.window_title_clearance, foo,
  1333.                      scr->window_title_texture,
  1334.                      scr->resizebar_texture,
  1335.                      scr->window_title_pixel, 
  1336. #ifdef DRAWSTRING_PLUGIN
  1337.                      W_STRING_FTITLE,
  1338. #endif
  1339.                      &scr->window_title_gc, 
  1340.                      &scr->title_font);
  1341.     
  1342.     XSaveContext(dpy, window, wWinContext, (XPointer)&wwin->client_descriptor);
  1343.  
  1344.     wwin->frame->flags.is_client_window_frame = 1;
  1345.     wwin->frame->flags.justification = wPreferences.title_justification;
  1346.  
  1347.     wFrameWindowChangeTitle(wwin->frame, title);
  1348.  
  1349.     /* setup button images */
  1350.     wWindowUpdateButtonImages(wwin);
  1351.  
  1352.     /* hide buttons */
  1353.     wFrameWindowHideButton(wwin->frame, WFF_RIGHT_BUTTON);
  1354.     
  1355.     wwin->frame->child = wwin;
  1356.     
  1357.     wwin->frame->workspace = wwin->screen_ptr->current_workspace;
  1358.     
  1359. #ifdef XKB_BUTTON_HINT
  1360.     if (wPreferences.modelock)
  1361.         wwin->frame->on_click_language = windowLanguageClick;
  1362. #endif
  1363.         
  1364.     wwin->frame->on_click_right = windowCloseClick;
  1365.     
  1366.     wwin->frame->on_mousedown_titlebar = titlebarMouseDown;
  1367.     wwin->frame->on_dblclick_titlebar = titlebarDblClick;
  1368.     
  1369.     wwin->frame->on_mousedown_resizebar = resizebarMouseDown;
  1370.  
  1371.     wwin->client.y += wwin->frame->top_width;
  1372.     XReparentWindow(dpy, wwin->client_win, wwin->frame->core->window, 
  1373.             0, wwin->frame->top_width);
  1374.  
  1375.     wWindowConfigure(wwin, wwin->frame_x, wwin->frame_y, 
  1376.              wwin->client.width, wwin->client.height);
  1377.  
  1378.     /* setup the frame descriptor */
  1379.     wwin->frame->core->descriptor.handle_mousedown = frameMouseDown;
  1380.     wwin->frame->core->descriptor.parent = wwin;
  1381.     wwin->frame->core->descriptor.parent_type = WCLASS_WINDOW;
  1382.  
  1383.  
  1384.     XLowerWindow(dpy, window);
  1385.     XMapSubwindows(dpy, wwin->frame->core->window);
  1386.     
  1387.     /* setup stacking descriptor */
  1388.     if (
  1389. #ifdef removed
  1390.     wPreferences.on_top_transients && 
  1391. #endif
  1392.     wwin->transient_for!=None
  1393.     && wwin->transient_for!=scr->root_win) {
  1394.     WWindow *tmp;
  1395.     tmp = wWindowFor(wwin->transient_for);
  1396.     if (tmp)
  1397.         wwin->frame->core->stacking->child_of = tmp->frame->core;
  1398.     } else {
  1399.     wwin->frame->core->stacking->child_of = NULL;
  1400.     }
  1401.     
  1402.  
  1403.     if (!scr->focused_window) {
  1404.     /* first window on the list */
  1405.     wwin->next = NULL;
  1406.     wwin->prev = NULL;
  1407.     scr->focused_window = wwin;
  1408.     } else {
  1409.     WWindow *tmp;
  1410.  
  1411.     /* add window at beginning of focus window list */
  1412.     tmp = scr->focused_window;
  1413.     while (tmp->prev)
  1414.       tmp = tmp->prev;
  1415.     tmp->prev = wwin;
  1416.     wwin->next = tmp;
  1417.     wwin->prev = NULL;
  1418.     }
  1419.  
  1420.     if (wwin->flags.is_gnustep == 0)
  1421.       wFrameWindowChangeState(wwin->frame, WS_UNFOCUSED);
  1422.  
  1423. /*    if (wPreferences.auto_focus)*/
  1424.     wSetFocusTo(scr, wwin);
  1425.  
  1426.     wWindowResetMouseGrabs(wwin);
  1427.  
  1428.     wWindowSetKeyGrabs(wwin);
  1429.  
  1430.     UpdateSwitchMenu(wwin->screen_ptr, wwin, ACTION_ADD);    
  1431.  
  1432.     return wwin;
  1433. }
  1434.  
  1435.  
  1436. /*
  1437.  *---------------------------------------------------------------------- 
  1438.  * wUnmanageWindow--
  1439.  *     Removes the frame window from a window and destroys all data
  1440.  * related to it. The window will be reparented back to the root window
  1441.  * if restore is True.
  1442.  * 
  1443.  * Side effects:
  1444.  *     Everything related to the window is destroyed and the window
  1445.  * is removed from the window lists. Focus is set to the previous on the
  1446.  * window list.
  1447.  *---------------------------------------------------------------------- 
  1448.  */
  1449. void
  1450. wUnmanageWindow(WWindow *wwin, Bool restore, Bool destroyed)
  1451. {
  1452.     WCoreWindow *frame = wwin->frame->core;
  1453.     WWindow *owner = NULL;
  1454.     WWindow *newFocusedWindow = NULL;
  1455.     int wasFocused;
  1456.     WScreen *scr = wwin->screen_ptr;
  1457.  
  1458.  
  1459. #ifdef KWM_HINTS
  1460.     wwin->frame->workspace = -1;
  1461.  
  1462.     wKWMUpdateClientWorkspace(wwin);
  1463. #endif
  1464.  
  1465.     /* First close attribute editor window if open */
  1466.     if (wwin->flags.inspector_open) {
  1467.     wCloseInspectorForWindow(wwin);
  1468.     }
  1469.  
  1470.     /* Close window menu if it's open for this window */
  1471.     if (wwin->flags.menu_open_for_me) {
  1472.     CloseWindowMenu(scr);
  1473.     }
  1474.  
  1475.     if (!destroyed) {
  1476.     if (!wwin->flags.internal_window)
  1477.         XRemoveFromSaveSet(dpy, wwin->client_win);
  1478.  
  1479.     XSelectInput(dpy, wwin->client_win, NoEventMask);
  1480.  
  1481.     XUngrabButton(dpy, AnyButton, AnyModifier, wwin->client_win);
  1482.     XUngrabKey(dpy, AnyKey, AnyModifier, wwin->client_win);
  1483.     }
  1484.  
  1485.     XUnmapWindow(dpy, frame->window);
  1486.  
  1487.     XUnmapWindow(dpy, wwin->client_win);
  1488.  
  1489.     /* deselect window */
  1490.     wSelectWindow(wwin, False);
  1491.     
  1492.     /* remove all pending events on window */
  1493.     /* I think this only matters for autoraise */
  1494.     if (wPreferences.raise_delay) 
  1495.        WMDeleteTimerWithClientData(wwin->frame->core);
  1496.  
  1497.     XFlush(dpy);
  1498.  
  1499.     UpdateSwitchMenu(scr, wwin, ACTION_REMOVE);
  1500.  
  1501.     /* reparent the window back to the root */
  1502.     if (restore)
  1503.     wClientRestore(wwin);
  1504.  
  1505.     if (wwin->transient_for!=scr->root_win) {
  1506.     owner = wWindowFor(wwin->transient_for);
  1507.     if (owner) {
  1508.         if (!owner->flags.semi_focused) {
  1509.         owner = NULL;
  1510.         } else {
  1511.         owner->flags.semi_focused = 0;
  1512.         }
  1513.     }
  1514.     }
  1515.  
  1516.     wasFocused = wwin->flags.focused;
  1517.     
  1518.     /* remove from window focus list */
  1519.     if (!wwin->prev && !wwin->next) {
  1520.     /* was the only window */
  1521.     scr->focused_window = NULL;
  1522.     newFocusedWindow = NULL;
  1523.     } else {
  1524.     WWindow *tmp;
  1525.  
  1526.     if (wwin->prev)
  1527.       wwin->prev->next = wwin->next;
  1528.     if (wwin->next)
  1529.       wwin->next->prev = wwin->prev;
  1530.     else {
  1531.         scr->focused_window = wwin->prev;
  1532.         scr->focused_window->next = NULL;
  1533.     }
  1534.  
  1535.     if (wPreferences.focus_mode==WKF_CLICK) {
  1536.  
  1537.            /* if in click to focus mode and the window
  1538.             * was a transient, focus the owner window  
  1539.             */
  1540.            tmp = NULL;
  1541.            if (wPreferences.focus_mode==WKF_CLICK) {
  1542.                tmp = wWindowFor(wwin->transient_for);
  1543.                if (tmp && (!tmp->flags.mapped || WFLAGP(tmp, no_focusable))) {
  1544.                    tmp = NULL;
  1545.                }
  1546.            }
  1547.            /* otherwise, focus the next one in the focus list */
  1548.            if (!tmp) {
  1549.               tmp = scr->focused_window;
  1550.               while (tmp) {               /* look for one in the window list first */
  1551.                  if (!WFLAGP(tmp, no_focusable) && !WFLAGP(tmp, skip_window_list)
  1552.                      && (tmp->flags.mapped || tmp->flags.shaded))
  1553.                      break;
  1554.                  tmp = tmp->prev;
  1555.               }
  1556.               if (!tmp) {                 /* if unsuccessful, choose any focusable window */
  1557.                  tmp = scr->focused_window;
  1558.                  while (tmp) {
  1559.                     if (!WFLAGP(tmp, no_focusable)
  1560.                          && (tmp->flags.mapped || tmp->flags.shaded))
  1561.                          break;
  1562.                     tmp = tmp->prev;
  1563.                  }
  1564.               }
  1565.            }
  1566.  
  1567.        newFocusedWindow = tmp;
  1568.  
  1569.     } else if (wPreferences.focus_mode==WKF_SLOPPY
  1570.            || wPreferences.focus_mode==WKF_POINTER) {
  1571.             unsigned int mask;
  1572.             int foo;
  1573.             Window bar, win;
  1574.  
  1575.             /*  This is to let the root window get the keyboard input
  1576.              * if Sloppy focus mode and no other window get focus.
  1577.              * This way keybindings will not freeze.
  1578.              */
  1579.             tmp = NULL;
  1580.             if (XQueryPointer(dpy, scr->root_win, &bar, &win,
  1581.                               &foo, &foo, &foo, &foo, &mask))
  1582.                 tmp = wWindowFor(win);
  1583.             if (tmp == wwin)
  1584.                 tmp = NULL;
  1585.         newFocusedWindow = tmp;
  1586.         } else {
  1587.         newFocusedWindow = NULL;
  1588.     }
  1589.     }
  1590.  
  1591.     if (!wwin->flags.internal_window) {
  1592. #ifdef GNOME_STUFF
  1593.     wGNOMERemoveClient(wwin);
  1594. #endif
  1595. #ifdef KWM_HINTS
  1596.     wKWMSendEventMessage(wwin, WKWMRemoveWindow);
  1597. #endif
  1598.     }
  1599.  
  1600. #ifdef DEBUG
  1601.     printf("destroying window %x frame %x\n", (unsigned)wwin->client_win,
  1602.        (unsigned)frame->window);
  1603. #endif
  1604.  
  1605.     if (wasFocused) {
  1606.     if (newFocusedWindow != owner && owner) {
  1607.         if (wwin->flags.is_gnustep == 0)
  1608.           wFrameWindowChangeState(owner->frame, WS_UNFOCUSED);
  1609.     }
  1610.     wSetFocusTo(scr, newFocusedWindow);
  1611.     }
  1612.     wWindowDestroy(wwin);
  1613.     XFlush(dpy);
  1614. }
  1615.  
  1616.  
  1617. void
  1618. wWindowMap(WWindow *wwin)
  1619. {
  1620.     XMapWindow(dpy, wwin->frame->core->window);
  1621.     if (!wwin->flags.shaded) {
  1622.     /* window will be remapped when getting MapNotify */
  1623.     XSelectInput(dpy, wwin->client_win, 
  1624.              wwin->event_mask & ~StructureNotifyMask);
  1625.     XMapWindow(dpy, wwin->client_win);
  1626.     XSelectInput(dpy, wwin->client_win, wwin->event_mask);
  1627.  
  1628.     wwin->flags.mapped = 1;
  1629.     }
  1630. }
  1631.  
  1632.  
  1633. void
  1634. wWindowUnmap(WWindow *wwin)
  1635. {
  1636.     wwin->flags.mapped = 0;
  1637.  
  1638.     /* prevent window withdrawal when getting UnmapNotify */
  1639.     XSelectInput(dpy, wwin->client_win, 
  1640.          wwin->event_mask & ~StructureNotifyMask);
  1641.     XUnmapWindow(dpy, wwin->client_win);
  1642.     XSelectInput(dpy, wwin->client_win, wwin->event_mask);
  1643.  
  1644.     XUnmapWindow(dpy, wwin->frame->core->window);
  1645. }
  1646.  
  1647.  
  1648.  
  1649. void
  1650. wWindowFocus(WWindow *wwin, WWindow *owin)
  1651. {
  1652.     WWindow *nowner;
  1653.     WWindow *oowner;
  1654.  
  1655. #ifdef KEEP_XKB_LOCK_STATUS
  1656.     if (wPreferences.modelock) {
  1657.         XkbLockGroup(dpy, XkbUseCoreKbd, wwin->frame->languagemode);
  1658.     }
  1659. #endif /* KEEP_XKB_LOCK_STATUS */
  1660.  
  1661.     wwin->flags.semi_focused = 0;
  1662.  
  1663.     if (wwin->flags.is_gnustep == 0)
  1664.       wFrameWindowChangeState(wwin->frame, WS_FOCUSED);
  1665.  
  1666.     wwin->flags.focused = 1;
  1667.  
  1668.     wWindowResetMouseGrabs(wwin);
  1669.  
  1670.     UpdateSwitchMenu(wwin->screen_ptr, wwin, ACTION_CHANGE_STATE);
  1671.  
  1672.     if (owin == wwin || !owin)
  1673.     return;
  1674.  
  1675.     nowner = wWindowFor(wwin->transient_for);
  1676.  
  1677.     /* new window is a transient for the old window */
  1678.     if (nowner == owin) {
  1679.     owin->flags.semi_focused = 1;
  1680.     wWindowUnfocus(nowner);
  1681.     return;
  1682.     }
  1683.  
  1684.     oowner = wWindowFor(owin->transient_for);
  1685.  
  1686.     /* new window is owner of old window */
  1687.     if (wwin == oowner) {
  1688.     wWindowUnfocus(owin);
  1689.     return;
  1690.     }
  1691.  
  1692.     if (!nowner) {
  1693.     wWindowUnfocus(owin);
  1694.     return;
  1695.     }
  1696.  
  1697.     /* new window has same owner of old window */
  1698.     if (oowner == nowner) {
  1699.     /* prevent unfocusing of owner */
  1700.     oowner->flags.semi_focused = 0;
  1701.     wWindowUnfocus(owin);
  1702.     oowner->flags.semi_focused = 1;
  1703.  
  1704.     return;
  1705.     }
  1706.  
  1707.     /* nowner != NULL && oowner != nowner */
  1708.     nowner->flags.semi_focused = 1;
  1709.     wWindowUnfocus(nowner);
  1710.     wWindowUnfocus(owin);
  1711. }
  1712.  
  1713.  
  1714. void
  1715. wWindowUnfocus(WWindow *wwin)
  1716. {
  1717.     CloseWindowMenu(wwin->screen_ptr);
  1718.  
  1719.     if (wwin->flags.is_gnustep == 0)
  1720.       wFrameWindowChangeState(wwin->frame, wwin->flags.semi_focused 
  1721.                 ? WS_PFOCUSED : WS_UNFOCUSED);
  1722.  
  1723.     if (wwin->transient_for!=None 
  1724.     && wwin->transient_for!=wwin->screen_ptr->root_win) {
  1725.     WWindow *owner;
  1726.     owner = wWindowFor(wwin->transient_for);
  1727.     if (owner && owner->flags.semi_focused) {
  1728.         owner->flags.semi_focused = 0;
  1729.         if (owner->flags.mapped || owner->flags.shaded) {
  1730.         wWindowUnfocus(owner);
  1731.         wFrameWindowPaint(owner->frame);
  1732.         }
  1733.     }
  1734.     }
  1735.     wwin->flags.focused = 0;
  1736.  
  1737.     wWindowResetMouseGrabs(wwin);
  1738.  
  1739.     UpdateSwitchMenu(wwin->screen_ptr, wwin, ACTION_CHANGE_STATE);
  1740.  
  1741. }
  1742.  
  1743.  
  1744.  
  1745. /*
  1746.  *----------------------------------------------------------------------
  1747.  * 
  1748.  * wWindowConstrainSize--
  1749.  *     Constrains size for the client window, taking the maximal size,
  1750.  * window resize increments and other size hints into account.
  1751.  * 
  1752.  * Returns:
  1753.  *     The closest size to what was given that the client window can 
  1754.  * have.
  1755.  * 
  1756.  *---------------------------------------------------------------------- 
  1757.  */
  1758. void
  1759. wWindowConstrainSize(WWindow *wwin, int *nwidth, int *nheight)
  1760. {
  1761.     int width = *nwidth;
  1762.     int height = *nheight;
  1763.     int winc = 1;
  1764.     int hinc = 1;
  1765.     int minW = 1, minH = 1;
  1766.     int maxW = wwin->screen_ptr->scr_width*2;
  1767.     int maxH = wwin->screen_ptr->scr_height*2;
  1768.     int minAX = -1, minAY = -1;
  1769.     int maxAX = -1, maxAY = -1;
  1770.     int baseW = 0;
  1771.     int baseH = 0;
  1772.  
  1773.     if (wwin->normal_hints) {
  1774.     winc = wwin->normal_hints->width_inc;
  1775.     hinc = wwin->normal_hints->height_inc;
  1776.     minW = wwin->normal_hints->min_width;
  1777.     minH = wwin->normal_hints->min_height;
  1778.     maxW = wwin->normal_hints->max_width;
  1779.     maxH = wwin->normal_hints->max_height;
  1780.     if (wwin->normal_hints->flags & PAspect) {
  1781.         minAX = wwin->normal_hints->min_aspect.x;
  1782.         minAY = wwin->normal_hints->min_aspect.y;
  1783.         maxAX = wwin->normal_hints->max_aspect.x;
  1784.         maxAY = wwin->normal_hints->max_aspect.y;
  1785.     }
  1786.     }
  1787.  
  1788.     if (width < minW)
  1789.       width = minW;
  1790.     if (height < minH)
  1791.       height = minH;
  1792.  
  1793.     if (width > maxW)
  1794.       width = maxW;
  1795.     if (height > maxH) 
  1796.       height = maxH;
  1797.  
  1798.     /* aspect ratio code borrowed from olwm */
  1799.     if (minAX > 0) {
  1800.     /* adjust max aspect ratio */
  1801.     if (!(maxAX == 1 && maxAY == 1) && width * maxAY > height * maxAX) {
  1802.         if (maxAX > maxAY) {
  1803.         height = (width * maxAY) / maxAX;
  1804.         if (height > maxH) {
  1805.             height = maxH;
  1806.             width = (height * maxAX) / maxAY;
  1807.         }
  1808.         } else {
  1809.         width = (height * maxAX) / maxAY;
  1810.         if (width > maxW) {
  1811.             width = maxW;
  1812.             height = (width * maxAY) / maxAX;
  1813.         }
  1814.         }
  1815.     }
  1816.  
  1817.     /* adjust min aspect ratio */
  1818.     if (!(minAX == 1 && minAY == 1) && width * minAY < height * minAX) {
  1819.         if (minAX > minAY) {
  1820.         height = (width * minAY) / minAX;
  1821.         if (height < minH) {
  1822.             height = minH;
  1823.             width = (height * minAX) / minAY;
  1824.         }
  1825.         } else {
  1826.         width = (height * minAX) / minAY;
  1827.         if (width < minW) {
  1828.             width = minW;
  1829.             height = (width * minAY) / minAX;
  1830.         }
  1831.         }
  1832.     }
  1833.     }
  1834.  
  1835.     if (baseW != 0) {
  1836.     width = (((width - baseW) / winc) * winc) + baseW;
  1837.     } else {
  1838.     width = (((width - minW) / winc) * winc) + minW;
  1839.     }
  1840.  
  1841.     if (baseW != 0) {
  1842.     height = (((height - baseH) / hinc) * hinc) + baseH;
  1843.     } else {
  1844.     height = (((height - minH) / hinc) * hinc) + minH;
  1845.     }
  1846.  
  1847.     /* broken stupid apps may cause preposterous values for these.. */
  1848.     if (width > 0)
  1849.     *nwidth = width;
  1850.     if (height > 0)
  1851.     *nheight = height;
  1852. }
  1853.  
  1854.  
  1855. void
  1856. wWindowChangeWorkspace(WWindow *wwin, int workspace)
  1857. {
  1858.     WScreen *scr = wwin->screen_ptr;
  1859.     WApplication *wapp;
  1860.     int unmap = 0;
  1861.  
  1862.     if (workspace >= scr->workspace_count || workspace < 0 
  1863.     || workspace == wwin->frame->workspace)
  1864.     return;
  1865.  
  1866.     if (workspace != scr->current_workspace) {
  1867.     /* Sent to other workspace. Unmap window */
  1868.     if ((wwin->flags.mapped
  1869.          || wwin->flags.shaded
  1870.          || (wwin->flags.miniaturized && !wPreferences.sticky_icons))
  1871.         && !IS_OMNIPRESENT(wwin) && !wwin->flags.changing_workspace) {
  1872.  
  1873.         wapp = wApplicationOf(wwin->main_window);
  1874.         if (wapp) {
  1875.         wapp->last_workspace = workspace;
  1876.         }
  1877.         if (wwin->flags.miniaturized) {
  1878.         if (wwin->icon) {
  1879.             XUnmapWindow(dpy, wwin->icon->core->window);
  1880.             wwin->icon->mapped = 0;
  1881.         }
  1882.         } else {
  1883.         unmap = 1;
  1884.         wSetFocusTo(scr, NULL);
  1885.         }
  1886.     }
  1887.     } else {
  1888.     /* brought to current workspace. Map window */
  1889.     if (wwin->flags.miniaturized && !wPreferences.sticky_icons) {
  1890.         if (wwin->icon) {
  1891.         XMapWindow(dpy, wwin->icon->core->window);
  1892.         wwin->icon->mapped = 1;
  1893.         }
  1894.     } else if (!wwin->flags.mapped && 
  1895.         !(wwin->flags.miniaturized || wwin->flags.hidden)) {
  1896.         wWindowMap(wwin);
  1897.     }
  1898.     }
  1899.     if (!IS_OMNIPRESENT(wwin)) {
  1900.     wwin->frame->workspace = workspace;
  1901.         UpdateSwitchMenu(scr, wwin, ACTION_CHANGE_WORKSPACE);
  1902.     }
  1903. #ifdef GNOME_STUFF
  1904.     wGNOMEUpdateClientStateHint(wwin, True);
  1905. #endif
  1906. #ifdef KWM_HINTS
  1907.     wKWMUpdateClientWorkspace(wwin);
  1908.     wKWMSendEventMessage(wwin, WKWMChangedClient);
  1909. #endif
  1910.     if (unmap) {
  1911.     wWindowUnmap(wwin);
  1912.     }
  1913. }
  1914.  
  1915.  
  1916. void
  1917. wWindowSynthConfigureNotify(WWindow *wwin)
  1918. {
  1919.     XEvent sevent;
  1920.  
  1921.     sevent.type = ConfigureNotify;
  1922.     sevent.xconfigure.display = dpy;
  1923.     sevent.xconfigure.event = wwin->client_win;
  1924.     sevent.xconfigure.window = wwin->client_win;
  1925.  
  1926.     sevent.xconfigure.x = wwin->client.x;
  1927.     sevent.xconfigure.y = wwin->client.y;
  1928.     sevent.xconfigure.width = wwin->client.width;
  1929.     sevent.xconfigure.height = wwin->client.height;
  1930.  
  1931.     sevent.xconfigure.border_width = wwin->old_border_width;
  1932.     if (WFLAGP(wwin, no_titlebar))
  1933.     sevent.xconfigure.above = None;
  1934.     else
  1935.         sevent.xconfigure.above = wwin->frame->titlebar->window;
  1936.  
  1937.     sevent.xconfigure.override_redirect = False;
  1938.     XSendEvent(dpy, wwin->client_win, False, StructureNotifyMask, &sevent);
  1939. #ifdef KWM_HINTS
  1940.     wKWMSendEventMessage(wwin, WKWMChangedClient);
  1941. #endif
  1942.     XFlush(dpy);
  1943. }
  1944.  
  1945.  
  1946. /*
  1947.  *----------------------------------------------------------------------
  1948.  * wWindowConfigure--
  1949.  *     Configures the frame, decorations and client window to the 
  1950.  * specified geometry. The geometry is not checked for validity,
  1951.  * wWindowConstrainSize() must be used for that. 
  1952.  *     The size parameters are for the client window, but the position is
  1953.  * for the frame.
  1954.  *     The client window receives a ConfigureNotify event, according
  1955.  * to what ICCCM says.
  1956.  * 
  1957.  * Returns:
  1958.  *     None
  1959.  * 
  1960.  * Side effects:
  1961.  *     Window size and position are changed and client window receives
  1962.  * a ConfigureNotify event.
  1963.  *---------------------------------------------------------------------- 
  1964.  */
  1965. void 
  1966. wWindowConfigure(wwin, req_x, req_y, req_width, req_height)
  1967. WWindow *wwin;
  1968. int req_x, req_y;               /* new position of the frame */
  1969. int req_width, req_height;           /* new size of the client */
  1970. {
  1971.     int synth_notify = False;
  1972.     int resize;
  1973.     
  1974.     resize = (req_width!=wwin->client.width
  1975.           || req_height!=wwin->client.height);
  1976.     /* 
  1977.      * if the window is being moved but not resized then
  1978.      * send a synthetic ConfigureNotify
  1979.      */
  1980.     if ((req_x!=wwin->frame_x || req_y!=wwin->frame_y) && !resize) {
  1981.     synth_notify = True;
  1982.     }
  1983.         
  1984.     if (WFLAGP(wwin, dont_move_off))
  1985.     wScreenBringInside(wwin->screen_ptr, &req_x, &req_y, 
  1986.                req_width, req_height);
  1987.     if (resize) {
  1988.     if (req_width < MIN_WINDOW_SIZE)
  1989.         req_width = MIN_WINDOW_SIZE;
  1990.     if (req_height < MIN_WINDOW_SIZE)
  1991.         req_height = MIN_WINDOW_SIZE;
  1992.     
  1993.     /* If growing, resize inner part before frame,
  1994.      * if shrinking, resize frame before.
  1995.      * This will prevent the frame (that can have a different color) 
  1996.      * to be exposed, causing flicker */
  1997.     if (req_height > wwin->frame->core->height
  1998.         || req_width > wwin->frame->core->width)
  1999.         XResizeWindow(dpy, wwin->client_win, req_width, req_height);
  2000.  
  2001.     if (wwin->flags.shaded) {
  2002.         wFrameWindowConfigure(wwin->frame, req_x, req_y,
  2003.                   req_width, wwin->frame->core->height);
  2004.         wwin->old_geometry.height = req_height;
  2005.     } else {
  2006.         int h;
  2007.  
  2008.         h = req_height + wwin->frame->top_width 
  2009.         + wwin->frame->bottom_width;
  2010.  
  2011.         wFrameWindowConfigure(wwin->frame, req_x, req_y, req_width, h);
  2012.     }
  2013.  
  2014.     if (!(req_height > wwin->frame->core->height
  2015.         || req_width > wwin->frame->core->width))
  2016.         XResizeWindow(dpy, wwin->client_win, req_width, req_height);
  2017.  
  2018.     wwin->client.x = req_x;
  2019.     wwin->client.y = req_y + wwin->frame->top_width;
  2020.     wwin->client.width = req_width;
  2021.     wwin->client.height = req_height;
  2022.     } else {
  2023.     wwin->client.x = req_x;
  2024.     wwin->client.y = req_y + wwin->frame->top_width;
  2025.  
  2026.     XMoveWindow(dpy, wwin->frame->core->window, req_x, req_y);
  2027.     }
  2028.     wwin->frame_x = req_x;
  2029.     wwin->frame_y = req_y;
  2030.     if (!WFLAGP(wwin, no_border)) {
  2031.     wwin->client.x += FRAME_BORDER_WIDTH;
  2032.     wwin->client.y += FRAME_BORDER_WIDTH;
  2033.     }
  2034.  
  2035. #ifdef SHAPE
  2036.     if (wShapeSupported && wwin->flags.shaped && resize) {
  2037.     wWindowSetShape(wwin);
  2038.     }
  2039. #endif
  2040.  
  2041.     if (synth_notify)
  2042.     wWindowSynthConfigureNotify(wwin);
  2043.     XFlush(dpy);
  2044. }
  2045.  
  2046.  
  2047. void 
  2048. wWindowMove(wwin, req_x, req_y)
  2049. WWindow *wwin;
  2050. int req_x, req_y;               /* new position of the frame */
  2051. {
  2052. #ifdef CONFIGURE_WINDOW_WHILE_MOVING
  2053.     int synth_notify = False;
  2054.  
  2055.     /* Send a synthetic ConfigureNotify event for every window movement. */
  2056.     if ((req_x!=wwin->frame_x || req_y!=wwin->frame_y)) {
  2057.     synth_notify = True;
  2058.     }
  2059. #else
  2060.     /* A single synthetic ConfigureNotify event is sent at the end of
  2061.      * a completed (opaque) movement in moveres.c */
  2062. #endif
  2063.  
  2064.     if (WFLAGP(wwin, dont_move_off))
  2065.     wScreenBringInside(wwin->screen_ptr, &req_x, &req_y,
  2066.                wwin->frame->core->width, wwin->frame->core->height);
  2067.  
  2068.     wwin->client.x = req_x;
  2069.     wwin->client.y = req_y + wwin->frame->top_width;
  2070.     if (!WFLAGP(wwin, no_border)) {
  2071.     wwin->client.x += FRAME_BORDER_WIDTH;
  2072.     wwin->client.y += FRAME_BORDER_WIDTH;
  2073.     }
  2074.  
  2075.     XMoveWindow(dpy, wwin->frame->core->window, req_x, req_y);
  2076.  
  2077.     wwin->frame_x = req_x;
  2078.     wwin->frame_y = req_y;
  2079.  
  2080. #ifdef CONFIGURE_WINDOW_WHILE_MOVING
  2081.     if (synth_notify)
  2082.     wWindowSynthConfigureNotify(wwin);
  2083. #endif
  2084. }
  2085.  
  2086.  
  2087. void
  2088. wWindowUpdateButtonImages(WWindow *wwin)
  2089. {
  2090.     WScreen *scr = wwin->screen_ptr;
  2091.     Pixmap pixmap, mask;
  2092.     WFrameWindow *fwin = wwin->frame;
  2093.  
  2094.     if (WFLAGP(wwin, no_titlebar))
  2095.     return;
  2096.  
  2097.     /* miniaturize button */
  2098.  
  2099.     if (!WFLAGP(wwin, no_miniaturize_button)) {
  2100.     if (wwin->wm_gnustep_attr
  2101.         && wwin->wm_gnustep_attr->flags & GSMiniaturizePixmapAttr) {
  2102.         pixmap = wwin->wm_gnustep_attr->miniaturize_pixmap;
  2103.     
  2104.         if (wwin->wm_gnustep_attr->flags&GSMiniaturizeMaskAttr) {
  2105.         mask = wwin->wm_gnustep_attr->miniaturize_mask;
  2106.         } else {
  2107.         mask = None;
  2108.         }
  2109.  
  2110.         if (fwin->lbutton_image
  2111.         && (fwin->lbutton_image->image != pixmap
  2112.             || fwin->lbutton_image->mask != mask)) {
  2113.         wPixmapDestroy(fwin->lbutton_image);
  2114.         fwin->lbutton_image = NULL;
  2115.         }
  2116.     
  2117.         if (!fwin->lbutton_image) {
  2118.         fwin->lbutton_image = wPixmapCreate(scr, pixmap, mask);
  2119.         fwin->lbutton_image->client_owned = 1;
  2120.         fwin->lbutton_image->client_owned_mask = 1;
  2121.         }
  2122.     } else {
  2123.         if (fwin->lbutton_image && !fwin->lbutton_image->shared) {
  2124.         wPixmapDestroy(fwin->lbutton_image);
  2125.         }
  2126.         fwin->lbutton_image = scr->b_pixmaps[WBUT_ICONIFY];
  2127.     }
  2128.     }
  2129.  
  2130. #ifdef XKB_BUTTON_HINT
  2131.     if (!WFLAGP(wwin, no_language_button)) {
  2132.         if (fwin->languagebutton_image &&  
  2133.         !fwin->languagebutton_image->shared) {
  2134.         wPixmapDestroy(fwin->languagebutton_image);
  2135.         }
  2136.     fwin->languagebutton_image = 
  2137.         scr->b_pixmaps[WBUT_XKBGROUP1 + fwin->languagemode];
  2138.     }
  2139. #endif
  2140.  
  2141.     /* close button */
  2142.  
  2143. /* redefine WFLAGP to MGFLAGP to allow broken close operation */
  2144. #define MGFLAGP(wwin, FLAG)    (wwin)->client_flags.FLAG
  2145.  
  2146.     if (!WFLAGP(wwin, no_close_button)) {
  2147.         if (wwin->wm_gnustep_attr 
  2148.         && wwin->wm_gnustep_attr->flags & GSClosePixmapAttr) {
  2149.             pixmap = wwin->wm_gnustep_attr->close_pixmap;
  2150.     
  2151.             if (wwin->wm_gnustep_attr->flags&GSCloseMaskAttr)
  2152.                  mask = wwin->wm_gnustep_attr->close_mask;
  2153.             else
  2154.                  mask = None;
  2155.  
  2156.            if (fwin->rbutton_image && (fwin->rbutton_image->image != pixmap
  2157.                        || fwin->rbutton_image->mask != mask)) {
  2158.            wPixmapDestroy(fwin->rbutton_image);
  2159.            fwin->rbutton_image = NULL;
  2160.        }
  2161.             
  2162.            if (!fwin->rbutton_image) {
  2163.                fwin->rbutton_image = wPixmapCreate(scr, pixmap, mask);
  2164.                fwin->rbutton_image->client_owned = 1;
  2165.                fwin->rbutton_image->client_owned_mask = 1;
  2166.        }
  2167.  
  2168.     } else if (WFLAGP(wwin, kill_close)) {
  2169.  
  2170.         if (fwin->rbutton_image && !fwin->rbutton_image->shared)
  2171.         wPixmapDestroy(fwin->rbutton_image);
  2172.  
  2173.         fwin->rbutton_image = scr->b_pixmaps[WBUT_KILL];
  2174.         
  2175.     } else if (MGFLAGP(wwin, broken_close)) {
  2176.  
  2177.         if (fwin->rbutton_image && !fwin->rbutton_image->shared) 
  2178.         wPixmapDestroy(fwin->rbutton_image);
  2179.  
  2180.         fwin->rbutton_image = scr->b_pixmaps[WBUT_BROKENCLOSE];
  2181.  
  2182.     } else {
  2183.  
  2184.         if (fwin->rbutton_image && !fwin->rbutton_image->shared) 
  2185.         wPixmapDestroy(fwin->rbutton_image);
  2186.  
  2187.         fwin->rbutton_image = scr->b_pixmaps[WBUT_CLOSE];
  2188.     }
  2189.     }
  2190.  
  2191.     /* force buttons to be redrawn */
  2192.     fwin->flags.need_texture_change = 1;
  2193.     wFrameWindowPaint(fwin);
  2194. }
  2195.  
  2196.  
  2197. /*
  2198.  *---------------------------------------------------------------------------
  2199.  * wWindowConfigureBorders--
  2200.  *     Update window border configuration according to attribute flags.
  2201.  * 
  2202.  *--------------------------------------------------------------------------- 
  2203.  */
  2204. void 
  2205. wWindowConfigureBorders(WWindow *wwin)
  2206. {
  2207.     if (wwin->frame) {
  2208.     int flags;
  2209.     int newy, oldh;
  2210.  
  2211.     flags = WFF_LEFT_BUTTON|WFF_RIGHT_BUTTON;
  2212. #ifdef XKB_BUTTON_HINT
  2213.     flags |= WFF_LANGUAGE_BUTTON;
  2214. #endif
  2215.     if (!WFLAGP(wwin, no_titlebar))
  2216.         flags |= WFF_TITLEBAR;
  2217.     if (!WFLAGP(wwin, no_resizebar))
  2218.         flags |= WFF_RESIZEBAR;
  2219.     if (!WFLAGP(wwin, no_border))
  2220.         flags |= WFF_BORDER;
  2221.     if (wwin->flags.shaded)
  2222.         flags |= WFF_IS_SHADED;
  2223.  
  2224.     oldh = wwin->frame->top_width;
  2225.     wFrameWindowUpdateBorders(wwin->frame, flags);
  2226.     if (oldh != wwin->frame->top_width) {
  2227.         newy = wwin->frame_y + oldh - wwin->frame->top_width;
  2228.  
  2229.         XMoveWindow(dpy, wwin->client_win, 0, wwin->frame->top_width);
  2230.         wWindowConfigure(wwin, wwin->frame_x, newy,
  2231.                  wwin->client.width, wwin->client.height);
  2232.     }
  2233.  
  2234.     flags = 0;
  2235.     if (!WFLAGP(wwin, no_miniaturize_button)
  2236.         && wwin->frame->flags.hide_left_button)
  2237.         flags |= WFF_LEFT_BUTTON;
  2238.  
  2239. #ifdef XKB_BUTTON_HINT
  2240.     if (!WFLAGP(wwin, no_language_button)
  2241.             && wwin->frame->flags.hide_language_button)
  2242.         flags |= WFF_LANGUAGE_BUTTON;
  2243. #endif
  2244.  
  2245.     if (!WFLAGP(wwin, no_close_button)
  2246.         && wwin->frame->flags.hide_right_button)
  2247.         flags |= WFF_RIGHT_BUTTON;
  2248.  
  2249.     if (flags!=0) {
  2250.         wWindowUpdateButtonImages(wwin);
  2251.         wFrameWindowShowButton(wwin->frame, flags);
  2252.     }
  2253.  
  2254.     flags = 0;
  2255.     if (WFLAGP(wwin, no_miniaturize_button)
  2256.         && !wwin->frame->flags.hide_left_button)
  2257.         flags |= WFF_LEFT_BUTTON;
  2258.  
  2259. #ifdef XKB_BUTTON_HINT
  2260.     if (WFLAGP(wwin, no_language_button)
  2261.         && !wwin->frame->flags.hide_language_button)
  2262.         flags |= WFF_LANGUAGE_BUTTON;
  2263. #endif
  2264.  
  2265.     if (WFLAGP(wwin, no_close_button)
  2266.         && !wwin->frame->flags.hide_right_button)
  2267.         flags |= WFF_RIGHT_BUTTON;
  2268.  
  2269.     if (flags!=0)
  2270.         wFrameWindowHideButton(wwin->frame, flags);
  2271.  
  2272. #ifdef SHAPE
  2273.     if (wShapeSupported && wwin->flags.shaped) {
  2274.         wWindowSetShape(wwin);
  2275.     }
  2276. #endif
  2277.     }
  2278. }
  2279.  
  2280.  
  2281. void
  2282. wWindowSaveState(WWindow *wwin)
  2283. {
  2284.     CARD32 data[10];
  2285.     int i;
  2286.  
  2287.     memset(data, 0, sizeof(CARD32)*10);
  2288.     data[0] = wwin->frame->workspace;
  2289.     data[1] = wwin->flags.miniaturized;
  2290.     data[2] = wwin->flags.shaded;
  2291.     data[3] = wwin->flags.hidden;
  2292.  
  2293.     for (i = 0; i < MAX_WINDOW_SHORTCUTS; i++) {
  2294.     if (wwin->screen_ptr->shortcutWindows[i] &&
  2295.         WMCountInBag(wwin->screen_ptr->shortcutWindows[i], wwin))
  2296.         data[9] |= 1<<i;
  2297.     }
  2298.     XChangeProperty(dpy, wwin->client_win, _XA_WINDOWMAKER_STATE,
  2299.             _XA_WINDOWMAKER_STATE, 32, PropModeReplace,
  2300.             (unsigned char *)data, 10);
  2301. }
  2302.  
  2303.  
  2304. static int
  2305. getSavedState(Window window, WSavedState **state)
  2306. {
  2307.     Atom type_ret;
  2308.     int fmt_ret;
  2309.     unsigned long nitems_ret;
  2310.     unsigned long bytes_after_ret;
  2311.     CARD32 *data;
  2312.     
  2313.     if (XGetWindowProperty(dpy, window, _XA_WINDOWMAKER_STATE, 0, 10,
  2314.                True, _XA_WINDOWMAKER_STATE,
  2315.                &type_ret, &fmt_ret, &nitems_ret, &bytes_after_ret,
  2316.                (unsigned char **)&data)!=Success || !data)
  2317.       return 0;
  2318.     
  2319.     *state = malloc(sizeof(WSavedState));
  2320.  
  2321.     if (*state) {
  2322.     (*state)->workspace = data[0];
  2323.     (*state)->miniaturized = data[1];
  2324.     (*state)->shaded = data[2];
  2325.     (*state)->hidden = data[3];
  2326.     (*state)->use_geometry = data[4];
  2327.     (*state)->x = data[5];
  2328.     (*state)->y = data[6];
  2329.     (*state)->w = data[7];
  2330.     (*state)->h = data[8];
  2331.     (*state)->window_shortcuts = data[9];
  2332.     }
  2333.     XFree(data);
  2334.     
  2335.     if (*state && type_ret==_XA_WINDOWMAKER_STATE)
  2336.       return 1;
  2337.     else 
  2338.       return 0;
  2339. }
  2340.  
  2341.  
  2342. #ifdef SHAPE
  2343. void
  2344. wWindowClearShape(WWindow *wwin)
  2345. {
  2346.     XShapeCombineMask(dpy, wwin->frame->core->window, ShapeBounding,
  2347.               0, wwin->frame->top_width, None, ShapeSet);
  2348.     XFlush(dpy);
  2349. }
  2350.  
  2351. void 
  2352. wWindowSetShape(WWindow *wwin)
  2353. {
  2354.     XRectangle rect[2];
  2355.     int count;
  2356. #ifdef OPTIMIZE_SHAPE
  2357.     XRectangle *rects;
  2358.     XRectangle *urec;
  2359.     int ordering;
  2360.  
  2361.     /* only shape is the client's */
  2362.     if (WFLAGP(wwin, no_titlebar) && WFLAGP(wwin, no_resizebar)) {
  2363.     goto alt_code;
  2364.     }
  2365.     
  2366.     /* Get array of rectangles describing the shape mask */
  2367.     rects = XShapeGetRectangles(dpy, wwin->client_win, ShapeBounding,
  2368.                 &count, &ordering);
  2369.     if (!rects) {
  2370.     goto alt_code;
  2371.     }
  2372.  
  2373.     urec = malloc(sizeof(XRectangle)*(count+2));
  2374.     if (!urec) {
  2375.     XFree(rects);
  2376.     goto alt_code;
  2377.     }
  2378.  
  2379.     /* insert our decoration rectangles in the rect list */
  2380.     memcpy(urec, rects, sizeof(XRectangle)*count);
  2381.     XFree(rects);
  2382.  
  2383.     if (!WFLAGP(wwin, no_titlebar)) {
  2384.     urec[count].x = -1;
  2385.     urec[count].y = -1 - wwin->frame->top_width;
  2386.     urec[count].width = wwin->frame->core->width + 2;
  2387.     urec[count].height = wwin->frame->top_width + 1;
  2388.     count++;
  2389.     }
  2390.     if (!WFLAGP(wwin, no_resizebar)) {
  2391.     urec[count].x = -1;
  2392.     urec[count].y = wwin->frame->core->height 
  2393.         - wwin->frame->bottom_width - wwin->frame->top_width;
  2394.     urec[count].width = wwin->frame->core->width + 2;
  2395.     urec[count].height = wwin->frame->bottom_width + 1;
  2396.     count++;
  2397.     }
  2398.  
  2399.     /* shape our frame window */
  2400.     XShapeCombineRectangles(dpy, wwin->frame->core->window, ShapeBounding,
  2401.                 0, wwin->frame->top_width, urec, count,
  2402.                 ShapeSet, Unsorted);
  2403.     XFlush(dpy);
  2404.     free(urec);
  2405.     return;
  2406.  
  2407. alt_code:
  2408. #endif /* OPTIMIZE_SHAPE */
  2409.     count = 0;
  2410.     if (!WFLAGP(wwin, no_titlebar)) {
  2411.         rect[count].x = -1;
  2412.         rect[count].y = -1;
  2413.     rect[count].width = wwin->frame->core->width + 2;
  2414.     rect[count].height = wwin->frame->top_width + 1;
  2415.         count++;
  2416.     }
  2417.     if (!WFLAGP(wwin, no_resizebar)) {
  2418.     rect[count].x = -1;
  2419.     rect[count].y = wwin->frame->core->height - wwin->frame->bottom_width;
  2420.     rect[count].width = wwin->frame->core->width + 2;
  2421.     rect[count].height = wwin->frame->bottom_width + 1;
  2422.     count++;
  2423.     }
  2424.     if (count > 0) {
  2425.     XShapeCombineRectangles(dpy, wwin->frame->core->window, ShapeBounding,
  2426.                 0, 0, rect, count, ShapeSet, Unsorted);
  2427.     }
  2428.     XShapeCombineShape(dpy, wwin->frame->core->window, ShapeBounding,
  2429.                0, wwin->frame->top_width, wwin->client_win,
  2430.                ShapeBounding, (count > 0 ? ShapeUnion : ShapeSet));
  2431.     XFlush(dpy);
  2432. }
  2433. #endif /* SHAPE */
  2434.  
  2435. /* ====================================================================== */
  2436.  
  2437. static FocusMode
  2438. getFocusMode(WWindow *wwin)
  2439. {
  2440.     FocusMode mode;
  2441.  
  2442.     if ((wwin->wm_hints) && (wwin->wm_hints->flags & InputHint)) {
  2443.     if (wwin->wm_hints->input == True) {
  2444.         if (wwin->protocols.TAKE_FOCUS)
  2445.           mode = WFM_LOCALLY_ACTIVE;
  2446.         else
  2447.           mode = WFM_PASSIVE;
  2448.     } else {
  2449.         if (wwin->protocols.TAKE_FOCUS)
  2450.           mode = WFM_GLOBALLY_ACTIVE;
  2451.         else
  2452.           mode = WFM_NO_INPUT;
  2453.     }
  2454.     } else {
  2455.     mode = WFM_PASSIVE;
  2456.     }
  2457.     return mode;
  2458. }
  2459.  
  2460.  
  2461. void
  2462. wWindowSetKeyGrabs(WWindow *wwin)
  2463. {
  2464.     int i;
  2465.     WShortKey *key;
  2466.  
  2467.     for (i=0; i<WKBD_LAST; i++) {
  2468.     key = &wKeyBindings[i];
  2469.  
  2470.     if (key->keycode==0)
  2471.         continue;
  2472.     if (key->modifier!=AnyModifier) {
  2473.         XGrabKey(dpy, key->keycode, key->modifier|LockMask,
  2474.         wwin->frame->core->window, True, GrabModeAsync, GrabModeAsync);
  2475. #ifdef NUMLOCK_HACK
  2476.         /* Also grab all modifier combinations possible that include,
  2477.          * LockMask, ScrollLockMask and NumLockMask, so that keygrabs
  2478.          * work even if the NumLock/ScrollLock key is on.
  2479.          */
  2480.         wHackedGrabKey(key->keycode, key->modifier,
  2481.                wwin->frame->core->window, True, GrabModeAsync, 
  2482.                GrabModeAsync);
  2483. #endif
  2484.     }
  2485.     XGrabKey(dpy, key->keycode, key->modifier,
  2486.          wwin->frame->core->window, True, GrabModeAsync, GrabModeAsync);
  2487.     }
  2488.  
  2489. #ifndef LITE
  2490.     wRootMenuBindShortcuts(wwin->frame->core->window);
  2491. #endif
  2492. }
  2493.  
  2494.  
  2495.  
  2496. void
  2497. wWindowResetMouseGrabs(WWindow *wwin)
  2498. {
  2499.     /* Mouse grabs can't be done on the client window because of
  2500.      * ICCCM and because clients that try to do the same will crash.
  2501.      * 
  2502.      * But there is a problem wich makes tbar buttons of unfocused
  2503.      * windows not usable as the click goes to the frame window instead
  2504.      * of the button itself. Must figure a way to fix that.
  2505.      */
  2506.  
  2507.     XUngrabButton(dpy, AnyButton, AnyModifier, wwin->client_win);
  2508.  
  2509.     if (!WFLAGP(wwin, no_bind_mouse)) {
  2510.     /* grabs for Meta+drag */
  2511.     wHackedGrabButton(AnyButton, MOD_MASK, wwin->client_win,
  2512.               True, ButtonPressMask, GrabModeSync, 
  2513.               GrabModeAsync, None, None);
  2514.     }
  2515.     
  2516.     if (!wwin->flags.focused && !WFLAGP(wwin, no_focusable)
  2517.     && !wwin->flags.is_gnustep) {
  2518.     /* the passive grabs to focus the window */
  2519.     if (wPreferences.focus_mode == WKF_CLICK)
  2520.         XGrabButton(dpy, AnyButton, AnyModifier, wwin->client_win,
  2521.             True, ButtonPressMask, GrabModeSync, GrabModeAsync,
  2522.             None, None);
  2523.     }
  2524.     XFlush(dpy);
  2525. }
  2526.  
  2527.  
  2528. void
  2529. wWindowUpdateGNUstepAttr(WWindow *wwin, GNUstepWMAttributes *attr)
  2530. {
  2531.    if (attr->flags & GSExtraFlagsAttr) {
  2532.        if (MGFLAGP(wwin, broken_close) != 
  2533.        (attr->extra_flags & GSDocumentEditedFlag)) {
  2534.        wwin->client_flags.broken_close = !MGFLAGP(wwin, broken_close);
  2535.        wWindowUpdateButtonImages(wwin);
  2536.        }
  2537.    }
  2538. }
  2539.  
  2540.  
  2541. WMagicNumber
  2542. wWindowAddSavedState(char *instance, char *class, char *command,
  2543.                      pid_t pid, WSavedState *state)
  2544. {
  2545.     WWindowState *wstate;
  2546.  
  2547.     wstate = malloc(sizeof(WWindowState));
  2548.     if (!wstate)
  2549.         return 0;
  2550.  
  2551.     memset(wstate, 0, sizeof(WWindowState));
  2552.     wstate->pid = pid;
  2553.     if (instance)
  2554.         wstate->instance = wstrdup(instance);
  2555.     if (class)
  2556.         wstate->class = wstrdup(class);
  2557.     if (command)
  2558.         wstate->command = wstrdup(command);
  2559.     wstate->state = state;
  2560.  
  2561.     wstate->next = windowState;
  2562.     windowState = wstate;
  2563.  
  2564. #ifdef DEBUG
  2565.     printf("Added WindowState with ID %p, for %s.%s : \"%s\"\n", wstate, instance,
  2566.            class, command);
  2567. #endif
  2568.  
  2569.     return wstate;
  2570. }
  2571.  
  2572.  
  2573. #define SAME(x, y) (((x) && (y) && !strcmp((x), (y))) || (!(x) && !(y)))
  2574.  
  2575.  
  2576. WMagicNumber
  2577. wWindowGetSavedState(Window win)
  2578. {
  2579.     char *instance, *class, *command=NULL;
  2580.     WWindowState *wstate = windowState;
  2581.     char **argv;
  2582.     int argc;
  2583.  
  2584.     if (!wstate)
  2585.         return NULL;
  2586.  
  2587.     if (XGetCommand(dpy, win, &argv, &argc)) {
  2588.     if (argc > 0)
  2589.         command = FlattenStringList(argv, argc);
  2590.         XFreeStringList(argv);
  2591.     }
  2592.     if (!command)
  2593.         return NULL;
  2594.  
  2595.     if (PropGetWMClass(win, &class, &instance)) {
  2596.         while (wstate) {
  2597.             if (SAME(instance, wstate->instance) &&
  2598.                 SAME(class, wstate->class) &&
  2599.                 SAME(command, wstate->command)) {
  2600.                 break;
  2601.             }
  2602.             wstate = wstate->next;
  2603.         }
  2604.     } else {
  2605.         wstate = NULL;
  2606.     }
  2607.  
  2608. #ifdef DEBUG
  2609.     printf("Read WindowState with ID %p, for %s.%s : \"%s\"\n", wstate, instance,
  2610.            class, command);
  2611. #endif
  2612.  
  2613.     if (command) free(command);
  2614.     if (instance) XFree(instance);
  2615.     if (class) XFree(class);
  2616.  
  2617.     return wstate;
  2618. }
  2619.  
  2620.  
  2621. void 
  2622. wWindowDeleteSavedState(WMagicNumber id)
  2623. {
  2624.     WWindowState *tmp, *wstate=(WWindowState*)id;
  2625.  
  2626.     if (!wstate || !windowState)
  2627.         return;
  2628.  
  2629.     tmp = windowState;
  2630.     if (tmp==wstate) {
  2631.         windowState = wstate->next;
  2632. #ifdef DEBUG
  2633.         printf("Deleted WindowState with ID %p, for %s.%s : \"%s\"\n",
  2634.                wstate, wstate->instance, wstate->class, wstate->command);
  2635. #endif
  2636.         if (wstate->instance) free(wstate->instance);
  2637.         if (wstate->class)    free(wstate->class);
  2638.         if (wstate->command)  free(wstate->command);
  2639.         free(wstate->state);
  2640.         free(wstate);
  2641.     } else {
  2642.     while (tmp->next) {
  2643.         if (tmp->next==wstate) {
  2644.         tmp->next=wstate->next;
  2645. #ifdef DEBUG
  2646.                 printf("Deleted WindowState with ID %p, for %s.%s : \"%s\"\n",
  2647.                        wstate, wstate->instance, wstate->class, wstate->command);
  2648. #endif
  2649.                 if (wstate->instance) free(wstate->instance);
  2650.                 if (wstate->class)    free(wstate->class);
  2651.                 if (wstate->command)  free(wstate->command);
  2652.                 free(wstate->state);
  2653.                 free(wstate);
  2654.         break;
  2655.         }
  2656.         tmp = tmp->next;
  2657.     }
  2658.     }
  2659. }
  2660.  
  2661.  
  2662. void 
  2663. wWindowDeleteSavedStatesForPID(pid_t pid)
  2664. {
  2665.     WWindowState *tmp, *wstate;
  2666.  
  2667.     if (!windowState)
  2668.         return;
  2669.  
  2670.     tmp = windowState;
  2671.     if (tmp->pid == pid) {
  2672.     wstate = windowState;
  2673.         windowState = tmp->next;
  2674. #ifdef DEBUG
  2675.         printf("Deleted WindowState with ID %p, for %s.%s : \"%s\"\n",
  2676.                wstate, wstate->instance, wstate->class, wstate->command);
  2677. #endif
  2678.         if (wstate->instance) free(wstate->instance);
  2679.         if (wstate->class)    free(wstate->class);
  2680.         if (wstate->command)  free(wstate->command);
  2681.         free(wstate->state);
  2682.         free(wstate);
  2683.     } else {
  2684.     while (tmp->next) {
  2685.         if (tmp->next->pid==pid) {
  2686.         wstate = tmp->next;
  2687.         tmp->next = wstate->next;
  2688. #ifdef DEBUG
  2689.                 printf("Deleted WindowState with ID %p, for %s.%s : \"%s\"\n",
  2690.                        wstate, wstate->instance, wstate->class, wstate->command);
  2691. #endif
  2692.                 if (wstate->instance) free(wstate->instance);
  2693.                 if (wstate->class)    free(wstate->class);
  2694.                 if (wstate->command)  free(wstate->command);
  2695.                 free(wstate->state);
  2696.                 free(wstate);
  2697.         break;
  2698.         }
  2699.         tmp = tmp->next;
  2700.     }
  2701.     }    
  2702. }
  2703.  
  2704.  
  2705. /* ====================================================================== */
  2706.  
  2707. static void 
  2708. resizebarMouseDown(WCoreWindow *sender, void *data, XEvent *event)
  2709. {
  2710.     WWindow *wwin = data;
  2711.  
  2712. #ifndef NUMLOCK_HACK
  2713.     if ((event->xbutton.state & ValidModMask)
  2714.     != (event->xbutton.state & ~LockMask)) {
  2715.     wwarning(_("the NumLock, ScrollLock or similar key seems to be turned on.\n"\
  2716.         "Turn it off or some mouse actions and keyboard shortcuts will not work."));
  2717.     }
  2718. #endif
  2719.     
  2720.     event->xbutton.state &= ValidModMask;
  2721.     
  2722.     CloseWindowMenu(wwin->screen_ptr);
  2723.  
  2724.     if (wPreferences.focus_mode==WKF_CLICK 
  2725.     && !(event->xbutton.state&ControlMask)
  2726.     && !WFLAGP(wwin, no_focusable)) {
  2727.     wSetFocusTo(wwin->screen_ptr, wwin);
  2728.     }
  2729.  
  2730.     if (event->xbutton.button == Button1)
  2731.     wRaiseFrame(wwin->frame->core);
  2732.  
  2733.     if (event->xbutton.window != wwin->frame->resizebar->window) {
  2734.     if (XGrabPointer(dpy, wwin->frame->resizebar->window, True,
  2735.              ButtonMotionMask|ButtonReleaseMask|ButtonPressMask,
  2736.              GrabModeAsync, GrabModeAsync, None, 
  2737.              None, CurrentTime)!=GrabSuccess) {
  2738. #ifdef DEBUG0
  2739.         wwarning("pointer grab failed for window move");
  2740. #endif
  2741.         return;
  2742.     }
  2743.     }
  2744.     
  2745.     if (event->xbutton.state & MOD_MASK) {
  2746.     /* move the window */
  2747.     wMouseMoveWindow(wwin, event);
  2748.     XUngrabPointer(dpy, CurrentTime);
  2749.     } else {
  2750.         wMouseResizeWindow(wwin, event);
  2751.         XUngrabPointer(dpy, CurrentTime);
  2752.     }
  2753. }
  2754.  
  2755.  
  2756.  
  2757. static void 
  2758. titlebarDblClick(WCoreWindow *sender, void *data, XEvent *event)
  2759. {
  2760.     WWindow *wwin = data;
  2761.  
  2762.     event->xbutton.state &= ValidModMask;
  2763.  
  2764.     if (event->xbutton.button==Button1) {
  2765.     if (event->xbutton.state == 0) {
  2766.         if (!WFLAGP(wwin, no_shadeable)) {
  2767.         /* shade window */
  2768.         if (wwin->flags.shaded)
  2769.             wUnshadeWindow(wwin);
  2770.         else
  2771.             wShadeWindow(wwin);
  2772.         }
  2773.     } else {
  2774.         int dir = 0;
  2775.  
  2776.         if (event->xbutton.state & ControlMask)
  2777.         dir |= MAX_VERTICAL;
  2778.         
  2779.             if (event->xbutton.state & ShiftMask) {
  2780.         dir |= MAX_HORIZONTAL;
  2781.                 if (!(event->xbutton.state & ControlMask))
  2782.                     wSelectWindow(wwin, !wwin->flags.selected);
  2783.             }
  2784.  
  2785.         /* maximize window */
  2786.         if (dir !=0 && !WFLAGP(wwin, no_resizable)) {
  2787.         if (wwin->flags.maximized) 
  2788.             wUnmaximizeWindow(wwin);
  2789.          else
  2790.             wMaximizeWindow(wwin, dir);
  2791.         }
  2792.     }
  2793.     } else if (event->xbutton.button==Button3) {
  2794.     if (event->xbutton.state & MOD_MASK) {
  2795.         wHideOtherApplications(wwin);
  2796.     }
  2797.     } else if (event->xbutton.button==Button2) {
  2798.     wSelectWindow(wwin, !wwin->flags.selected);
  2799.     }
  2800. }
  2801.  
  2802.  
  2803. static void
  2804. frameMouseDown(WObjDescriptor *desc, XEvent *event)
  2805. {
  2806.     WWindow *wwin = desc->parent;
  2807.  
  2808.     event->xbutton.state &= ValidModMask;
  2809.     
  2810.     CloseWindowMenu(wwin->screen_ptr);
  2811.  
  2812.     if (wPreferences.focus_mode==WKF_CLICK
  2813.     && !(event->xbutton.state&ControlMask)
  2814.     && !WFLAGP(wwin, no_focusable)) {
  2815.     wSetFocusTo(wwin->screen_ptr, wwin);
  2816.     }
  2817.     if (event->xbutton.button == Button1) {
  2818.     wRaiseFrame(wwin->frame->core);
  2819.     }
  2820.     
  2821.     if (event->xbutton.state & MOD_MASK) {
  2822.     /* move the window */
  2823.     if (XGrabPointer(dpy, wwin->client_win, False, 
  2824.              ButtonMotionMask|ButtonReleaseMask|ButtonPressMask,
  2825.              GrabModeAsync, GrabModeAsync, None,
  2826.              None, CurrentTime)!=GrabSuccess) {
  2827. #ifdef DEBUG0
  2828.         wwarning("pointer grab failed for window move");
  2829. #endif
  2830.         return;
  2831.     }
  2832.     if (event->xbutton.button == Button3 && !WFLAGP(wwin, no_resizable))
  2833.         wMouseResizeWindow(wwin, event);
  2834.     else 
  2835.         wMouseMoveWindow(wwin, event);
  2836.     XUngrabPointer(dpy, CurrentTime);
  2837.     }
  2838. }
  2839.  
  2840.  
  2841. static void 
  2842. titlebarMouseDown(WCoreWindow *sender, void *data, XEvent *event)
  2843. {
  2844.     WWindow *wwin = (WWindow*)data;
  2845.  
  2846. #ifndef NUMLOCK_HACK
  2847.     if ((event->xbutton.state & ValidModMask)
  2848.     != (event->xbutton.state & ~LockMask)) {
  2849.     wwarning(_("the NumLock, ScrollLock or similar key seems to be turned on.\n"\
  2850.         "Turn it off or some mouse actions and keyboard shortcuts will not work."));
  2851.     }
  2852. #endif
  2853.     event->xbutton.state &= ValidModMask;
  2854.  
  2855.     CloseWindowMenu(wwin->screen_ptr);
  2856.  
  2857.     if (wPreferences.focus_mode==WKF_CLICK 
  2858.     && !(event->xbutton.state&ControlMask)
  2859.     && !WFLAGP(wwin, no_focusable)) {
  2860.     wSetFocusTo(wwin->screen_ptr, wwin);
  2861.     }
  2862.  
  2863.     if (event->xbutton.button == Button1
  2864.     || event->xbutton.button == Button2) {
  2865.     
  2866.     if (event->xbutton.button == Button1) {
  2867.         if (event->xbutton.state & MOD_MASK) {
  2868.         wLowerFrame(wwin->frame->core);
  2869.         } else {
  2870.         wRaiseFrame(wwin->frame->core);
  2871.         }
  2872.     }
  2873.     if ((event->xbutton.state & ShiftMask)
  2874.         && !(event->xbutton.state & ControlMask)) {
  2875.         wSelectWindow(wwin, !wwin->flags.selected);
  2876.         return;
  2877.     }
  2878.     if (event->xbutton.window != wwin->frame->titlebar->window
  2879.         && XGrabPointer(dpy, wwin->frame->titlebar->window, False,
  2880.                 ButtonMotionMask|ButtonReleaseMask|ButtonPressMask,
  2881.                 GrabModeAsync, GrabModeAsync, None, 
  2882.                 None, CurrentTime)!=GrabSuccess) {
  2883. #ifdef DEBUG0
  2884.         wwarning("pointer grab failed for window move");
  2885. #endif
  2886.         return;
  2887.     }
  2888.  
  2889.     /* move the window */
  2890.     wMouseMoveWindow(wwin, event);
  2891.  
  2892.     XUngrabPointer(dpy, CurrentTime);
  2893.     } else if (event->xbutton.button == Button3 && event->xbutton.state==0
  2894.            && !wwin->flags.internal_window
  2895.            && !WCHECK_STATE(WSTATE_MODAL)) {
  2896.     WObjDescriptor *desc;
  2897.  
  2898.     if (event->xbutton.window != wwin->frame->titlebar->window
  2899.         && XGrabPointer(dpy, wwin->frame->titlebar->window, False,
  2900.                 ButtonMotionMask|ButtonReleaseMask|ButtonPressMask,
  2901.                 GrabModeAsync, GrabModeAsync, None, 
  2902.                 None, CurrentTime)!=GrabSuccess) {
  2903. #ifdef DEBUG0
  2904.         wwarning("pointer grab failed for window move");
  2905. #endif
  2906.         return;
  2907.     }
  2908.  
  2909.     OpenWindowMenu(wwin, event->xbutton.x_root, 
  2910.                wwin->frame_y+wwin->frame->top_width, False);
  2911.  
  2912.     /* allow drag select */
  2913.     desc = &wwin->screen_ptr->window_menu->menu->descriptor;
  2914.     event->xany.send_event = True;
  2915.     (*desc->handle_mousedown)(desc, event);
  2916.     
  2917.     XUngrabPointer(dpy, CurrentTime);
  2918.     }
  2919. }
  2920.  
  2921.  
  2922.  
  2923. static void
  2924. windowCloseClick(WCoreWindow *sender, void *data, XEvent *event)
  2925. {
  2926.     WWindow *wwin = data;
  2927.  
  2928.     event->xbutton.state &= ValidModMask;
  2929.  
  2930.     CloseWindowMenu(wwin->screen_ptr);
  2931.  
  2932.     if (event->xbutton.button < Button1 || event->xbutton.button > Button3)
  2933.     return;
  2934.  
  2935.     /* if control-click, kill the client */
  2936.     if (event->xbutton.state & ControlMask) {
  2937.     wClientKill(wwin);
  2938.     } else {
  2939. #ifdef OLWM_HINTS
  2940.     if (wwin->flags.olwm_push_pin_out) {
  2941.  
  2942.         wwin->flags.olwm_push_pin_out = 0;
  2943.  
  2944.         wOLWMChangePushpinState(wwin, True);
  2945.  
  2946.         wFrameWindowUpdatePushButton(wwin->frame, False);
  2947.  
  2948.         return;
  2949.     }
  2950. #endif
  2951.     if (wwin->protocols.DELETE_WINDOW && event->xbutton.state==0) {
  2952.         /* send delete message */
  2953.         wClientSendProtocol(wwin, _XA_WM_DELETE_WINDOW, LastTimestamp);
  2954.     }
  2955.     }
  2956. }
  2957.  
  2958.  
  2959. static void
  2960. windowCloseDblClick(WCoreWindow *sender, void *data, XEvent *event)
  2961. {
  2962.     WWindow *wwin = data;
  2963.  
  2964.     CloseWindowMenu(wwin->screen_ptr);
  2965.  
  2966.     if (event->xbutton.button < Button1 || event->xbutton.button > Button3)
  2967.     return;
  2968.  
  2969.     /* send delete message */
  2970.     if (wwin->protocols.DELETE_WINDOW) {
  2971.     wClientSendProtocol(wwin, _XA_WM_DELETE_WINDOW, LastTimestamp);
  2972.     } else {
  2973.     wClientKill(wwin);
  2974.     }
  2975. }
  2976.  
  2977.  
  2978. #ifdef XKB_BUTTON_HINT
  2979. static void
  2980. windowLanguageClick(WCoreWindow *sender, void *data, XEvent *event)
  2981. {
  2982.     WWindow *wwin = data;
  2983.     WFrameWindow *fwin = wwin->frame;
  2984.     WScreen *scr = fwin->screen_ptr;
  2985.     XkbStateRec staterec;
  2986.     int tl;
  2987.  
  2988.     if (event->xbutton.button != Button1 && event->xbutton.button != Button3)
  2989.         return;
  2990.     tl = wwin->frame->languagemode;
  2991.     wwin->frame->languagemode = wwin->frame->last_languagemode;
  2992.     wwin->frame->last_languagemode = tl;
  2993.     wSetFocusTo(scr, wwin);
  2994.     wwin->frame->languagebutton_image = 
  2995.         wwin->frame->screen_ptr->b_pixmaps[WBUT_XKBGROUP1 + 
  2996.         wwin->frame->languagemode];
  2997.     wFrameWindowUpdateLanguageButton(wwin->frame);
  2998.     if (event->xbutton.button == Button3)
  2999.     return;
  3000.     wRaiseFrame(fwin->core);
  3001. }
  3002. #endif
  3003.  
  3004.  
  3005. static void
  3006. windowIconifyClick(WCoreWindow *sender, void *data, XEvent *event)
  3007. {
  3008.     WWindow *wwin = data;
  3009.  
  3010.     event->xbutton.state &= ValidModMask;
  3011.     
  3012.     CloseWindowMenu(wwin->screen_ptr);
  3013.  
  3014.     if (event->xbutton.button < Button1 || event->xbutton.button > Button3)
  3015.     return;
  3016.  
  3017.     if (wwin->protocols.MINIATURIZE_WINDOW && event->xbutton.state==0) {
  3018.     wClientSendProtocol(wwin, _XA_GNUSTEP_WM_MINIATURIZE_WINDOW,
  3019.                 LastTimestamp);
  3020.     } else {
  3021.     WApplication *wapp;
  3022.     if ((event->xbutton.state & ControlMask) ||
  3023.         (event->xbutton.button == Button3)) {
  3024.         
  3025.         wapp = wApplicationOf(wwin->main_window);
  3026.         if (wapp && !WFLAGP(wwin, no_appicon))
  3027.         wHideApplication(wapp);
  3028.     } else if (event->xbutton.state==0) {
  3029.         wIconifyWindow(wwin);
  3030.     }
  3031.     }
  3032. }
  3033.